Given a non-empty array of integers, return the k most frequent elements.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]
Example 2:
Input: nums = [1], k = 1 Output: [1]
Note:
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
LeetCode:链接
给定一个数组,返回其出现次数最多的k个元素,要求复杂度小于O(nlogn)。
1)首先扫一遍数组进行计数。接着用一个长度为k的最小堆,存储出现次数最多的元素(堆顶的元素最小,每次和堆顶的元素比较即可)。
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
countDict = {}
for num in nums:
countDict[num] = countDict.get(num, 0) + 1
heap = []
for key, value in countDict.items():
if len(heap) < k:
heap.append((key, value))
length = len(heap)
for i in range(0, length//2)[::-1]:
self.HeadAdjust(heap, i, length)
else:
if value > heap[0][1]:
heap.pop(0)
heap.insert(0, (key, value))
self.HeadAdjust(heap, 0, k)
return [x[0] for x in heap]
def HeadAdjust(self, nums, parent, length):
temp = nums[parent][1]
temp_node = nums[parent]
child = 2 * parent + 1
while child < length:
if child + 1 < length and nums[child+1][1] < nums[child][1]:
child += 1
if temp <= nums[child][1]:
break
nums[parent] = nums[child]
parent = child
child = 2 * parent + 1
nums[parent] = temp_node
也可以直接用heapq实现:
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
counts = collections.Counter(nums)
heap = []
for key, cnt in counts.items():
if len(heap) < k:
heapq.heappush(heap, (cnt, key))
else:
if heap[0][0] < cnt:
heapq.heappop(heap)
heapq.heappush(heap, (cnt, key))
return [x[1] for x in heap]
2)考虑使用时间复杂度只有O(n)的桶排序(bucket sort),同时消耗空间复杂度O(n)。桶排序就是空间换时间。1.遍历数组nums,利用字典cntDict统计各元素出现次数。 2. 遍历cntDict,利用嵌套列表freqList记录出现次数为i( i∈[1, n] )的所有元素 3. 逆序遍历freqList,将其中的前k个元素输出。
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
countDict = {}
res = []
for num in nums:
countDict[num] = countDict.get(num, 0) + 1
bucket = [[] for i in range(len(nums)+1)]
# 遍历字典 将key按照出现的次数放到对应的索引上 所以index5放了1 就说明1出现了5次
for key in countDict:
bucket[countDict[key]].append(key)
# 从后往前遍历
for i in range(len(bucket)-1, -1, -1):
if bucket[i]:
res.extend(bucket[i])
if len(res) >= k:
break
return res[:k]