• lintcode5


    Find K-th largest element in an array.
    Example
    In array [9,3,2,4,8], the 3rd largest element is 4.
    In array [1,2,3,4,5], the 1st largest element is 5, 2nd largest element is 4, 3rd largest element is 3 and etc.
    Challenge
    O(n) time, O(1) extra memory.
    Notice
    You can swap elements in the array

    Quick select. O(n)。一轮O(n)操作后把原问题化解为规模仅一半的问题(只接着搜其中一半了)
    实现:指针+递归。指针分为双指针和三指针两种写法,递归分为改变k和不改变k的写法。

    三指针:中间扫描,大扔左,小扔右,最后l左边的肯定全大的,r右边肯定全小的,lr加上中间的是==的。具体非对称写法还是“从左开始扫,左换动lm,右换动动r,中间只动m”。
    双指针:左右都找不合格的,找完互换。最后大扔左,小扔右,lr中间可能夹一个数。

    递归改变k:思路是return值的定义为这段里面第k大的数。所以如果去右段搜的话,新的k值要减去左边数的数量,因为很多更大的数已经不在我的考虑范围里了。
    递归不改变k:思路是return值的定义为全局nums第k个位置。我一直只传这个数,pass下去,我只保证我一直挪动位置最后答应你能把全局第k大的数移到k那个位置,时机合适麻烦你就直接把那个位置的东西拿走。

    细节:
    1.双指针写法里面的=加不加:指针对比要加=:全用l<=r的逻辑写,避免可能死循环(可能其中一根指针从没动过)。而数字对比不要加=:比如nums[l] > pivot,别担心==的情况没动指针,会在下面swap的时候动的。这个真的有点难记,这题三指针比双指针好写,没有这么detail。
    2.指针的问题最后检查时候都要看一下会不会有一轮过后,只有一根指针挪动全程的问题,因为这样会导致递归参数不变产生死循环的问题。尽量写法要让两根指针都动过,否则很危险,while循环or递归组合上不动指针,想想都恐怖。
    3.pivot直接把值取出来,是nums[(start+end)/2]而不是记录位置(start+end)/2。因为实现过程中动过各个数字了,可能下一轮在那个位置上的东西就不是最开始的对比对象了。
    4.题目定义第k大,有一个1的offset,要处理一下。比如找第一大的其实是计算机语言里的第0大。毕竟数组里第k个数跟着计算机语言的index定义,所以你最开始传进去要传k-1.

    1.三指针+不变k写法:

    public class Solution {
        /**
         * @param n: An integer
         * @param nums: An array
         * @return: the Kth largest element
         */
        public int kthLargestElement(int n, int[] nums) {
            // write your code here
            if (nums == null || nums.length == 0) {
                return -1;
            }
            return partitionAndFind(n - 1, nums, 0, nums.length - 1);
        }
        
        private int partitionAndFind(int k, int[] nums, int start, int end) {
            
            if (start == end) {
                return nums[k];
            }
            
            int l = start, m = start, r = end;
            int pivot = nums[(start + end) / 2];
            while (m <= r) {
                if (nums[m] > pivot) {
                    swap(nums, l, m);
                    l++;
                    m++;
                } else if (nums[m] < pivot) {
                    swap(nums, m, r);
                    r--;
                } else {
                    m++;
                }
            }
            
            if (k < l) {
                return partitionAndFind(k, nums, start, l - 1);
            } else if (k > r) {
                return partitionAndFind(k, nums, r + 1, end);
            } else {
                return nums[k];
            }
        }
        
        private void swap(int[] nums, int i, int j) {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }

    2.双指针+变k写法:

    public class Solution {
        /**
         * @param n: An integer
         * @param nums: An array
         * @return: the Kth largest element
         */
        public int kthLargestElement(int n, int[] nums) {
            // write your code here
            if (nums == null || nums.length == 0) {
                return -1;
            }
            return partitionAndFind(n, nums, 0, nums.length - 1);
        }
        
        private int partitionAndFind(int k, int[] nums, int start, int end) {
            
            if (start == end) {
                return nums[start];
            }
            
            int l = start, r = end;
            int pivot = nums[(start + end) / 2];
            while (l <= r) {
                while (l <= r && nums[l] > pivot) {
                    l++;
                }
                while (l <= r && nums[r] < pivot) {
                    r--;
                }
                if (l <= r) {
                    int temp = nums[l];
                    nums[l] = nums[r];
                    nums[r] = temp;
                    l++;
                    r--;
                }
            }
            
            if (start + k - 1 <= r) {
                return partitionAndFind(k, nums, start, r);
            } else if (start + k - 1 >= l) {
                return partitionAndFind(k - (l - start), nums, l, end);
            } else {
                return nums[r + 1];
            }
        }
    }
  • 相关阅读:
    适合于小团队产品迭代的APP测试流程
    【转】软件测试上线标准
    安全性测试之修改密码
    LoadRunner 实现监控Tomcat
    【转】人生应该接受的教育
    晓光聊《小厂如何做测试》
    由测试需要多少编程知识想到的
    12款很棒的浏览器兼容性测试工具推荐
    最近感悟测试人员需要的一种能力
    APP测试功能点总结
  • 原文地址:https://www.cnblogs.com/jasminemzy/p/9563695.html
Copyright © 2020-2023  润新知