赞
踩
题目
先遍历一遍数组,用哈希映射来记录每个值对应的频率。
把哈希映射转化为vector<pair<int,int>>或者二维数组的格式。
然后就可以使用和查找数组中第K大元素相同的方法来找到前K大频率的分割下标。
private: //产生随机数,将该随机下标的数与最后一个数调换位置,然后将数组分为左右两部分,返回分界线的下标 int randomPartition(vector<pair<int, int>>& dataPair, int leftIndex, int rightIndex) { srand((unsigned int)time(0)); int randnum = rand() % (rightIndex - leftIndex + 1) + leftIndex; swap(dataPair[randnum], dataPair[rightIndex]); int flagIndex = leftIndex; for (int i = leftIndex; i < rightIndex; i++) if (dataPair[i].second >= dataPair[rightIndex].second) { swap(dataPair[i], dataPair[flagIndex]); flagIndex++; } swap(dataPair[rightIndex], dataPair[flagIndex]); return flagIndex; } //快速选择 void quickSelect(vector<pair<int, int>>& dataPair, int leftIndex, int rightIndex, int k) { int flagIndex = randomPartition(dataPair, leftIndex, rightIndex); if (flagIndex == k) return; else flagIndex < k ? quickSelect(dataPair, flagIndex + 1, rightIndex, k) : quickSelect(dataPair, leftIndex, flagIndex - 1, k); } public: //快速排序 vector<int> topKFrequent(vector<int>& nums, int k) { vector<int> result; unordered_map<int, int> dataMap; for (auto& i : nums) //统计个数 dataMap[i]++; vector<pair<int, int>> dataPair(dataMap.begin(), dataMap.end());//把哈希映射变为一个数组 quickSelect(dataPair, 0, dataPair.size() - 1, k - 1); for (int i = 0; i < k; i++) result.push_back(dataPair[i].first); return result; }
时间复杂度:O(n)具体证明,参照算法导论。
空间复杂度:O(n)这里的n都指统计完频率后的个数n
先遍历一遍数组,用哈希映射来记录每个值对应的频率。
把哈希映射转化为vector<pair<int,int>>或者二维数组的格式。(先序步骤和上面的一样)
手撸大根堆:
对于序列【5,8,3,2,5,3,8,1,3】
其下标为【0,1,2,3,4,5,6,7,8】
把这个一维的数组像下图这样排列(是不是像一个树)
既然像树,那么父节点怎么和子节点连接起来呢,比如第二层的那个8,他的下标是1,那2的下标不就是1*2+1 = 3嘛,5的下标不就是1*2+2 = 4吗,其他的都是这样滴,那这样我们就可以构造一颗假树了。
在构造假树的时候,从下往上构造,顺便把最大的数放在根节点,比如左下角这一块,把2和3互换位置,这样最后构造的假树的最顶点就是整个树最大的数了,就是像下面这样。
注意,这里仅仅是巧合,好像显得每个根节点都是最大的,其实我们只能保证顶点的根节点是最大的。
先设置一个heapSize表示需要维护节点的多少
我们把最上面的8和最下面的2互换位置,heapSize减1,表示把最大的8删除了(heapSize-1也就管不到一维数组最后面的8了,所以就当是删除了)
进行互换后,需要对树重新进行维护,保证顶点是最大的
以此类推,直到删够K个节点,就得到了前K个高频元素了。
vector<int> topKFrequent2(vector<int>& nums, int k) { vector<int> result; unordered_map<int, int> dataMap; for (auto& i : nums) //统计个数 dataMap[i]++; vector<pair<int, int>> dataPair(dataMap.begin(), dataMap.end());//把哈希映射变为一个数组 int heapSize = dataPair.size(); buildMaxHeap(dataPair, heapSize); for (int i = dataPair.size() - 1; i >= (int)dataPair.size() - k; i--) { result.push_back(dataPair[0].first); swap(dataPair[i], dataPair[0]); heapSize--; maxHeapify(dataPair, 0, heapSize); } return result; } void buildMaxHeap(vector<pair<int, int>>& dataPair, int heapSize) { for (int i = heapSize / 2; i >= 0; i--) maxHeapify(dataPair, i, heapSize); } void maxHeapify(vector<pair<int, int>>& dataPair, int root, int heapSize) { int leftChild = root * 2 + 1, rightChild = root * 2 + 2, largestChild = root; if (leftChild<heapSize && dataPair[leftChild].second>dataPair[largestChild].second)largestChild = leftChild; if (rightChild<heapSize && dataPair[rightChild].second>dataPair[largestChild].second)largestChild = rightChild; if (largestChild != root) { swap(dataPair[root], dataPair[largestChild]); maxHeapify(dataPair, largestChild, heapSize); } }
时间复杂度:O(n log n)在维护的时候,只需要顺着一条树枝维护,所以消耗是log n
空间复杂度:O(n)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。