React

347. Top K Frequent Elements

Medium
Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]
Plain Text
복사
Example 2:
Input: nums = [1], k = 1 Output: [1]
Plain Text
복사
Constraints:
1 <= nums.length <=10510^{5}
k is in the range [1, the number of unique elements in the array].
It is guaranteed that the answer is unique.
Follow up: Your algorithm's time complexity must be better than O(n log n), where n is the array's size.

My solution

일단 reduce로 해시맵을 대신해서 객체에 담으려고 했다. 근데 이렇게 만드니까 프로퍼티들이 enumerable 속성이 false인 채(이게 default라서)로 들어가서 배열화하는 게 불가능한 것 같다.
그래서 그냥 보장되는 해시맵을 사용한다음.
entries()를 이용해서 [프로퍼티 키, 프로퍼티 값]으로 하나씩 감싼다음 {}의 객체 리터럴로 감싼 형태로 만들었다.
그리고 이 객체 리터럴을 destructuring 하면 {}가 벗겨지고 이걸 []로 감싸면 배열이 된다.
이 배열을 2번째 원소인 프로퍼티 값(빈도수)에 따라 sort한 다음 map으로 1번째 원소만 남은 배열을 새롭게 반환한다. 이 반환된 것을 바로 slice로 k만큼 잘라서 리턴했다.
굉장히 좋은 성능이 나왔다.
근데 훨씬 더 빠르면서 해시맵을 안 쓰고 객체 리터럴을 사용한 방식이 있었다. entries()를 쓰는 게 아니라 for...in 문을 사용해서 배열을 구성한다.
다른 사람 풀이

소스코드

/** * @param {number[]} nums * @param {number} k * @return {number[]} */ const topKFrequent = function (nums, k) { const myMap = new Map(); for (const x of nums) { if (myMap.has(x)) { myMap.set(x, myMap.get(x) + 1); } else { myMap.set(x, 1); } } return [...myMap.entries()] .sort((a, b) => b[1] - a[1]) .map(v => v[0]) .slice(0, k); }; test('TC1', () => { expect(topKFrequent([1, 1, 1, 2, 2, 3], 2)).toStrictEqual([1, 2]); }); test('TC2', () => { expect(topKFrequent([1], 1)).toStrictEqual([1]); }); test('TC3', () => { expect(topKFrequent([1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 4], 2)).toStrictEqual([3, 1]); });
JavaScript
복사