Given a non-empty array of integers, return the k most frequent elements.
For example, Given [1,1,1,2,2,3] and k = 2, return [1,2].
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.
思路
这是一个O(n)时间复杂度的算法,优于O(nlogn)
1. 求出每个数字的频次字典
2. 按照频次,装入桶中
3. 取前K个频次
Code
Python version
# -*- coding: utf-8 -*-
# @Time : 2017/7/14 15:44
# @Author : zhenguo
# @Email : guozhennianhua@163.com
# @File : topKFrequents.py
# @Software: PyCharm Community Edition
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
frequency_map = {}
bucket = []
# get frequency dict for nums
# also init bucket used to get max k frequency
for n in nums:
if frequency_map.get(n) is not None:
frequency_map[n] += 1
else:
frequency_map[n] = 1
bucket.append([])
bucket.append([])
# frequency of each element for nums as index for sort bucket
# if both frequency for two different elements are equal to i,
# then they would append at rear of bucket[i](type list).
for item in frequency_map:
frequency = frequency_map[item]
bucket[frequency].append(item)
# iterator bucket as descending
# if length of bucket[pos] is bigger zero, it indicates at least element whose frequency equals to pos exist
# and if length of res(type: list) is less k, then all elements in this bucket would append at res(type: list)
res = []
pos = len(bucket) - 1
while pos >= 0 and len(res) < k:
if len(bucket[pos]) > 0:
for item in bucket[pos]:
res.append(item)
pos -= 1
return res
然后发现桶的初始化不精简,作如下转化
def topKFrequent2(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
frequency_map = {}
# get frequency dict for nums
# also init bucket used to get max k frequency
for n in nums:
if frequency_map.get(n) is not None:
frequency_map[n] += 1
else:
frequency_map[n] = 1
# frequency of each element for nums as bucket index,
# if both frequency for two different elements are equal to i,
# then they would append at rear of bucket[i](type list).
###################################
# this is the only difference to method 1
# but it fails to get the right solution and one point is puzzling for me.
# By debug I found it would append an item at every element of bucket,
# and it's so puzzling!
bucket = [[]]*len(nums)
##################################
for item in frequency_map:
frequency = frequency_map[item]
bucket[frequency].append(item)
# iterator bucket as descending
# if length of bucket[pos] is bigger zero, it indicates at least element whose frequency equals to pos exist,
# and if length of res(type: list) is less k, then all elements in this bucket would append at res(type: list).
res = []
pos = len(bucket) - 1
while pos >= 0 and len(res) < k:
if len(bucket[pos]) > 0:
for item in bucket[pos]:
res.append(item)
pos -= 1
return res
浅复制导致的bug,因此改为深复制,
def topKFrequent3(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
frequency_map = {}
# get frequency dict for nums
# also init bucket used to get max k frequency
for n in nums:
if frequency_map.get(n) is not None:
frequency_map[n] += 1
else:
frequency_map[n] = 1
# frequency of each element for nums as bucket index,
# if both frequency for two different elements are equal to i,
# then they would append at rear of bucket[i](type list).
###################################
# The real reason for the question of topKFrequent2 method is shallow copy,
# so make a fix to deep copy
bucket = [[] for i in range(len(nums))]
##################################
for item in frequency_map:
frequency = frequency_map[item]
bucket[frequency].append(item)
# iterator bucket as descending
# if length of bucket[pos] is bigger zero, it indicates at least element whose frequency equals to pos exist,
# and if length of res(type: list) is less k, then all elements in this bucket would append at res(type: list).
res = []
pos = len(bucket) - 1
while pos >= 0 and len(res) < k:
if len(bucket[pos]) > 0:
for item in bucket[pos]:
res.append(item)
pos -= 1
return res