class RandomizedSet {
constructor() {
(this.map = new Map()), (this.arr = []);
}
insert(val) {
if (this.map.has(val)) return false;
this.map.set(val, this.arr.length);
this.arr.push(val);
return true;
}
remove(val) {
if (!this.map.has(val)) return false;
let deletedIndex = this.map.get(val);
this.arr[deletedIndex] = this.arr[this.arr.length - 1];
this.map.set(this.arr[deletedIndex], deletedIndex);
this.map.delete(val);
this.arr.pop();
return true;
}
getRandom() {
let randomIndex = Math.floor(Math.random() * this.arr.length);
return this.arr[randomIndex];
}
}
개인적으로 prototype
보다 class
로 구현하는게 더 직관적이라고 생각해서 class
를 사용하였다!
문제의 요구사항은 '중복을 허용하지 않는 자료구조 Set
을 직접 구현해볼 수 있나요?(시간 복잡도 O(1)으로' 였다. remove()
를 구현하는 부분에서 시간이 많이 걸렸다.. 문제 풀이를 설명하면 다음과 같다.
map
과 arr
를 준비한다.insert()
insert
메서드는 간단하다. map.set
을 이용해 val
값을 key로, this.arr.length
를 value로 mapping을 해준다. this.arr.length
는 해당 val
의 arr
내의 index를 의미한다.
여기서 this.arr.length - 1
이 아니라 this.arr.length
라고 해준 이유는 아직 this.arr
에 val
을 push
하지 않았기 때문이다.
이후 val
을 this.arr
에 push
해준다.
중복된 요소가 들어왔을 경우에는 map.has(val)
을 사용해 false
를 return
해준다.
getRandom()
Math.floor
로 감싸줬다.remove(val)
remove
메서드를 구현하는게 어려웠다. 내가 적용한 방법은 다음과 같다.
먼저, map
에 없는 요소를 삭제하려 하는 경우에는 false
를 return
한다.
이후, 삭제될 인덱스(=deletedIndex
)를 가져온다. this.map.get(val)
그리고 this.arr
의 삭제될 인덱스에 해당하는 요소를 요소 맨 끝 값으로 치환한다.(시간복잡도 O(1)으로 구현해야 하기 때문) 이렇게 되었을 때, 현재 this.arr
에는 this.arr[deletedIndex]
와 this.arr[this.arr.length - 1]
, 즉 this.arr
의 끝 요소가 중복되는 요소일 것이다.
this.map.set
을 이용해 치환된 this.arr[deletedIndex]
(원래 this.arr
의 끝에 있던 요소)가 deletedIndex
val
값을 가지게 된다. 이 말은, 원래는 this.arr[deletedIndex]
이 값은 this.arr
의 맨 끝의 인덱스를 mapping하고 있었는데, 현재는 deletedIndex
를 mapping하고 있다는 의미가 된다.
이제 arr
와 map
의 값을 모두 바꿨으니 map.delete(val)
을 이용해 들어온 val
에 해당하는 key
를 map
에서 찾아서 지워주고, arr
는 끝 요소와 치환했기 때문에, 끝 요소는 더 이상 필요가 없기에 pop()
을 통해 제거해준다.
수정, 지적을 환영합니다!
https://leetcode.com/problems/insert-delete-getrandom-o1/