休息了两天,开始继续写题。
[x] 自适应光学 [ ] 信息论 [ ] 智能图像处理 读题 给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。k 个最大的元素,而不是第 k 个不同的元素。O(n) 的算法解决此问题。
要求有二:
思路 第一思路 给了 vector,于是想到对数组排序后直接取数;但是要求 O(n) 时间复杂度,也就是如果要遍历的话只能遍历一遍或有限遍。O(kn)(大概)。
循环 k 次;创建一个等长的全 0 空数组第 i 次循环 跳过空数组对应位置不为 0 的位置 遇到的最大值为 max_num,记录对应位置,将空数组对应位置标记为 i 继续  考虑到 k 可能会比较大,如果 k 大于 size_nums 的一半,则改为找最小值。
于是有代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class  Solution  {public :int  findKthLargest (vector<int >& nums, int  k)  int  size_nums = nums.size ();if (k<size_nums-k){vector<int > max_nums (size_nums)  ;int  max_num = 0 ;int  pos = -1 ;for (int  i=0 ;i<=k;i++){0 ;-1 ;for (int  j=0 ;j<size_nums;j++){if (max_nums[j]!=0 ) continue ;return  max_num;else {int > min_nums (size_nums);int  min_num = 0 ;int  pos = -1 ;for (int  i=0 ;i<=k;i++){114514 ;-1 ;for (int  j=0 ;j<size_nums;j++){if (min_nums[j]!=0 ) continue ;return  min_num;
没超时,不过在一个小数列处出错了;于是把 
k<size_nums-k 改成了 
k<=size_nums-k。
现在在包含负数的地方出错了,应该是 max_num 初始化的问题?测试用例是 
[-1,2,0],k 是 2,结果是 0,我输出是 -1。
哦,不是,是我在 k>size_nums-k 时这部分的判断问题。第 k 大应当对应第 size_nums-k+1 小(比方说大小为 3 的数组中,第 2 大应该是第 2 小),而不是第 size_nums-k 小的。
于是有代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class  Solution  {public :int  findKthLargest (vector<int >& nums, int  k)  int  size_nums = nums.size ();if (k<=size_nums-k){vector<int > max_nums (size_nums)  ;int  max_num;int  pos;for (int  i=0 ;i<=k;i++){-114514 ;-1 ;for (int  j=0 ;j<size_nums;j++){if (max_nums[j]!=0 ) continue ;return  max_num;else {int > min_nums (size_nums);1 ;int  min_num;int  pos;for (int  i=0 ;i<=k;i++){114514 ;-1 ;for (int  j=0 ;j<size_nums;j++){if (min_nums[j]!=0 ) continue ;return  min_num;
提交,然后不出所料地超时了。这个测试用例的 nums 巨大一坨,size 是 35107,k 是 15991,也就是在中间,刚好是我最怕的那种。O(n^2) 了。
改变思路 需要 O(n),我的直觉告诉我用之前遇到过的单调栈来解。但是怎么解?
num 大于栈顶的数字吗?是。栈顶出栈,重新判断,直到 num 小于栈顶元素。  否。栈是否已满?是继续前进。  否num 入栈。     于是有代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class  Solution  {public :int  findKthLargest (vector<int >& nums, int  k)  int > s;int  size_nums = nums.size ();for  (int  i = 0 ; i < size_nums; i++) {if  (s.empty ()) push (nums[i]);if  (nums[i] > s.top ()) {pop ();continue ;else  {if  (s.size () >= k)continue ;else  {pop ();push (nums[i]);return  s.top ();
但是发现无法满足“筛选出最大的 k 的元素要求”,因为只能看到栈顶元素;如果一直出栈,那就会导致之前的元素都被丢掉。如果记录并重新入栈,则会导致时间复杂度飙升。
再次改变思路 首先,明白我需要什么。不能强行使用单调栈这种不适合的数据结构。我需要的是一个能存储包含 k 个数据的单调数据结构。假如有一个数据结构叫 ASD,有最大大小 k,那么我需要的是:
ASD 是否为满?不为满当前元素是最大的/最小的吗?是:直接放在开头/结尾  否:插入    为满:插入   但是插入到正确位置这个过程最大难免会有 O(k) 复杂度。有什么数据结构能满足我的要求?还是说我的思路是错误的?
官方题解 不是我能做出来的题,直接看题解。O(nlogn) 的时间复杂度,题干里却要求 O(n), 评论直接骂说左右脑互博。还有评论说直接秒解:
1 2 3 4 public  int  findKthLargest (int [] nums, int  k)  {return  nums[nums.length - k];
难绷。难道他是天才?
方法一:快速排序 类似于我的第一反应:先排序,后定位。但是使用的是快速排序,所以单次的时间复杂度是 O(logn) 而不是 O(n)。上面那个 Arrays.sort(nums) 应该就是 java 的快速排序库函数。
有官方代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Solution  {public :int  quickselect (vector<int > &nums, int  l, int  r, int  k)  if  (l == r)return  nums[k];int  partition = nums[l], i = l - 1 , j = r + 1 ;while  (i < j) {do  i++; while  (nums[i] < partition);do  j--; while  (nums[j] > partition);if  (i < j)swap (nums[i], nums[j]);if  (k <= j)return  quickselect (nums, l, j, k);else  return  quickselect (nums, j + 1 , r, k);int  findKthLargest (vector<int > &nums, int  k)  int  n = nums.size ();return  quickselect (nums, 0 , n - 1 , n - k);
不是我说,这几乎就是自己搓了一个 qsort 吧?不过 cpp 中似乎没有 qsort。搜了一下发现 qsort 用的也是快速排序。
方法二:基于堆排序的选择方法 见过但是不记得的数据结构:堆。有定义:
堆中某个节点的值总是不大于或不小于其父节点的值; 堆总是一棵完全二叉树。 确实是自带排序、方便维护和搜索的数据结构。
有官方代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class  Solution  {public :void  maxHeapify (vector<int >& a, int  i, int  heapSize)  int  l = i * 2  + 1 , r = i * 2  + 2 , largest = i;if  (l < heapSize && a[l] > a[largest]) {if  (r < heapSize && a[r] > a[largest]) {if  (largest != i) {swap (a[i], a[largest]);maxHeapify (a, largest, heapSize);void  buildMaxHeap (vector<int >& a, int  heapSize)  for  (int  i = heapSize / 2  - 1 ; i >= 0 ; --i) {maxHeapify (a, i, heapSize);int  findKthLargest (vector<int >& nums, int  k)  int  heapSize = nums.size ();buildMaxHeap (nums, heapSize);for  (int  i = nums.size () - 1 ; i >= nums.size () - k + 1 ; --i) {swap (nums[0 ], nums[i]);maxHeapify (nums, 0 , heapSize);return  nums[0 ];
收获 堆 快速排序 复习了单调栈(虽然没有用上)