寻找第k大的数

这周我们算法课讲了分治策略,讲到了如何运用分治策略来解决selection problem,于是我课后在leetcode找了一道寻找第k大的数的算法题,以加深自己的理解。这里是课上讲解的求第k小的大致思路,在解决第k大问题的时候我也是按照差不多的思路进行实现的

这里写图片描述
这里写图片描述

通过在数集中取一个随机的数v,通过它将数组划分为3个部分,分别是小于它,等于它和大于它的三个部分,然后通过k值,判断所求的数会在哪个集合,因而达到将集合快速缩小的目的。另外,通过保证每次v在讨论的数集中处在偏向中间的位置,可以使得算法复杂度最坏情况也是O(n)。
以下是leetcode中寻找数组中第k大的数的算法题及我的解答。由于每次将数组划分为3部分来进行讨论,情况比较复杂,我也没想到更简洁的实现方法,暂时先贴出自己最初版本的代码,其速度超过了61.8%的用户,还算可以接受吧。

这里写图片描述

百行代码预警(如果想到了更简洁的实现方法,我会另外写一篇博客)
#include <time.h>
#include <stdlib.h>
class Solution {
public:
    void swap(vector<int>::iterator iter, int i, int j) {
        int temp = iter[i];
        iter[i] = iter[j];
        iter[j] = temp;
    }
    int getIndex(vector<int>::iterator iter, int a, int b) {
        if (a == b) {
            return a;
        } else {
            if (b - a > 2) {
                float sl = 0, sr = 0;
                int index = (rand() % (b - a)) + a;
                for (int i = a; i <= b; i++) {
                    if (iter[i] <= iter[index]) {
                        sl = sl + 1;
                    }
                    if (iter[i] >= iter[index]) {
                        sr = sr + 1;
                    }
                }
                if ((sl / (b - a + 1) >= 0.25)&&(sr / (b - a + 1) >= 0.25)) {
                    return index;
                } else return getIndex(iter, a, b);
            } else return (rand() % (b - a)) + a;
        }
    }
    int findByRecursion(vector<int>::iterator iter, int k, int left, int right) {
        int i = left;
        int j = right;
        int randomIndex = getIndex(iter, left, right);
        int v = iter[randomIndex];
        int x = randomIndex;
        int y = x;
        int sr = 0, sl = 0, sv = 0;
        while (!((i >= x)&&(j <= y))) {
            bool flag = false;
            if (i < x) {
                while (iter[i] < v) {
                    i++;
                }
            }
            if (j > y) {
                while (iter[j] > v) {
                    j--;
                }
            }
            if ((i < x)&&(iter[i] == v)) {
                swap(iter, i, --x);
                flag = true;
            }
            if ((j > y)&&(iter[j] == v)) {
                swap(iter, j, ++y);
                flag = true;
            }
            if (!flag) {
                if ((i >= x)&&(j > y)) {
                    if (y == j - 1) {
                        swap(iter, x, j);
                        x++;
                        y++;
                    } else {
                        swap(iter, x, ++y);
                        swap(iter, j, x++);
                    }
                } else if ((i < x)&&(j <= y)) {
                    if (x == i + 1) {
                        swap(iter, y, i);
                        x--;
                        y--;
                    } else {
                        swap(iter, y, --x);
                        swap(iter, i, y--);
                    }
                } else if ((iter[i] > v)&&(iter[j] < v)) {
                    swap(iter, i, j);
                    i++;
                    j--;
                }
            }
        }
        sl = i - left;
        sv = y - x + 1;
        sr = right - j;
        if (k <= sr) {
            return findByRecursion(iter, k, y + 1, right);
        } else if (k <= sv + sr) {
            return v;
        } else {
            return findByRecursion(iter, k - sr - sv, left, x - 1);
        }
    }
    int findKthLargest(vector<int>& nums, int k) {
        vector<int>::iterator iter = nums.begin();
        srand (time(NULL));
        return findByRecursion(iter, k, 0, nums.size() - 1);
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值