49.数组中的第K个最大元素(快速排序)

49.数组中的第K个最大元素(快速排序)_第1张图片

49.数组中的第K个最大元素(快速排序)_第2张图片
利用快排序确定第几小的元素位置,相较于快排序不用完全整个数组的排序,而只是确定想要的位置即可

class Solution {
    Random random = new Random();

    public int findKthLargest(int[] nums, int k) {
        
        // 要找到的元素所在索引:  前K大,即倒数索引第K个(转换逆序大,为正序小,降序排列)
        int index = nums.length - k;
        
        int right = nums.length - 1;
        int left = 0;
        return quickSelect(nums, left, right, index);
    }

    public int quickSelect(int[] nums, int left, int right, int index) {
        
        // 得到分区值索引q,显然这个中间位置的索引q就是"第index小的数据"
        int q = randomPartition(nums, left, right);


        if (q == index) {
            // 如果刚好索引q就是想要的索引,则直接返回(递归结束的标志)
            return nums[q];

        } else {
            // 如果不是,比较q 与 index ,确定下次要检索的区间, 要么是[q+1, right], 要么就是[left, q-1]
            return q < index ? quickSelect(nums, q + 1, right, index) : quickSelect(nums, left, q - 1, index);
        }
    }

    public int randomPartition(int[] nums, int l, int r) {
        // 1. 随机数范围: [0, r-l+1) 同时加l, 则是 [l+1, r+1) =>[l, r]中随机选一个索引出来(取不到r+1)
        int i = random.nextInt(r - l + 1) + l;

        // 2. 交换nums[i], nums[r], 也就是将随机数先放在[l,r]最右边nums[r]上
        swap(nums, i, r);

        //将指定的随机值(位于数组的最右边位置)调整至中间位置,使得它的左边都比他小,右边都比他大,获取这个中间位置的索引
        //显然这个中间位置的索引就是"第index小的数据"
        return partition(nums, l, r);
    }


    //将指定的随机值(位于数组的最右边位置)调整至中间位置,使得它的左边都比他小,右边都比他大(体会这种算法的思想:先将小的放在最左边,将小的后的元素与最优位置相交换)
    public int partition(int[] nums, int l, int r) {
        // 3. 在调用当前方法的randomPartition方法中,已经确定了了随机数是nums[r]
        int x = nums[r];//这个x就是上面的随机数
        int i = l - 1;

        // 4.这个for循环操作就是将小于 x 的数都往[i, j]的左边区间设置,从而实现存在[l, i]区间,使得对应数值都 小于 x
        // 首先比较区间在[l, r]之间, 所以nums[j]中的    l<= j <= r
        for (int j = l; j < r; ++j) {
            // nums[j] 跟随机数 x 比较, 小于x的数都跟[l,r]左边区间交换,i=l-1,所以++i=l,初始索引就是l,
            if (nums[j] <= x) {
                swap(nums, ++i, j);//两两交换
            }
        }

        //5. 现在将x也就是nums[r] 跟nums[i+1]交换,从而分成两个区间[l.i]左, [i+2, r]右,左边区间的值都小于x
        swap(nums, i + 1, r);

        // 然后返回这个分区值(中间值得坐标)
        return i + 1;
    }

    public void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

你可能感兴趣的:(Leetcode刷题,排序算法,算法,leetcode)