3. 双指针-quick sort+quick select

思想:

使左右整体有序 找到pivot 左边小于等于pivot 右边大于等于pivot 然后左右再继续调用
有四个注意点:

  1. 始终是left<=right 原因在于 要不取等号的话再向下调用会有重复 quicksort(start, right) quicksort(left, end)left元素左右都被排序 导致会有stackoverflow 例子(1, 2); 所以取等号使左右彻底错开
  2. 从左到右找第一个大于等于pivot元素;从右向左找第一个小于等于pivot元素。之所以取等 是要尽可能使等于的元素左右分布均匀 如果不取等(1,1,1,1,1)集中在左边 不能尽可能平均下次左右元素的数量
  3. 最后left和right错开一位相邻,也有可能错开两位中间隔一个数 这点在quickselect最后一步讨论时比较关键
  4. 做题时注意是求升序还是降序

题目

  1. lt464 Sort O(nlogn) quick sort/merge sort
  2. 找第k大 215 Kth Largest Element in an Array
  • heap 用最小堆 n(logk)
  • quickselect O(n)
  1. 找前k大 544 Top k Largest Numbers 这个题有三种思路
  • heap 用最小堆 n(logk)
  • quickselect 找到第k大的数x 然后把大于等于x的都挑出来(具体要讨论 因为有可能有大于等于x的数) quickselect O(n) + sort O(klog(k)
  • quicksort 比较巧 给原版quicksort加一个条件 start>k就不排 相当于最后只有前k个数是有序的 O(n) 到 O(nlog(n))之间

lt464. Sort O(nlogn) quick sort/merge sort

public class Solution {
    /**
     * @param A: an integer array
     * @return: nothing
     */
    public void sortIntegers2(int[] nums) {
        // write your code here
        if(nums==null)
            return;
        int[] temp = new int[nums.length];
        // mergesort(nums, temp, 0, nums.length-1);
        quickSort(nums, 0, nums.length-1);
        
    }
    private void mergesort(int[] nums, int[] temp, int start, int end){
        if(start>=end)
            return;
        int mid = start+(end-start)/2;
        mergesort(nums, temp, start, mid);
        mergesort(nums, temp, mid+1, end);
        int left = start;
        int right = mid+1;
        int index = start;
        while(left<=mid && right<=end){
            if(nums[left]<nums[right]){
                temp[index] = nums[left];
                left++;
            }else{
                temp[index] = nums[right];
                right++;
            }
            index++;
        }
        while(left<=mid ){
            temp[index] = nums[left];
            left++;
            index++;
        }
         while(right<=end ){
            temp[index] = nums[right];
            right++;
            index++;
        }
        for(int i=start; i<=end; i++){
            nums[i] = temp[i];
        }
    }
    
    
    private void quickSort(int[] nums, int start, int end){
        if(start>=end)
            return;
        int left = start;
        int right = end;
        int pivot = nums[left+(right-left)/2];
        while(left<=right){
            while(left<=right && nums[left]<pivot)
                left++;
            while(left<=right && nums[right]>pivot)
                right--;
            if(left<=right){
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                left++;
                right--;
            }
        }
        quickSort(nums, start, right);
        quickSort(nums, left, end);
    }
}

215. Kth Largest Element in an Array

quickselect O(n)
heap O(nlogK)

class Solution {
    public int findKthLargest(int[] nums, int k) {
        // return heap(nums, k);
        return partition(nums, k);
    }
    public int heap(int[] nums, int k) {
        if(nums==null || k<=0 || nums.length<k)
            return -1;
        PriorityQueue<Integer> heap = new PriorityQueue<>(k);
        for(int i=0; i<nums.length; i++){
            if(heap.size()<k)
                heap.offer(nums[i]);
            else{
                heap.offer(Math.max(nums[i], heap.poll()));
            }
        }
        return heap.peek();
    }
    public int partition(int[] nums, int k) {
        if(nums==null || k<=0 || nums.length<k)
            return -1;
        return helper(nums, k, 0, nums.length-1);
    }
    private int helper(int[] nums, int k, int start, int end){
        if(start>=end)
            return nums[start];
        int left = start;
        int right = end;
        int mid = left+(right-left)/2;
        int pivot = nums[mid];
        while(left<=right){
            while(left<=right && nums[left]>pivot){
                left++;
            }
            while(left<=right && nums[right]<pivot){
                right--;
            }
            if(left<=right){
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                left++;
                right--;
            }
        }
        if(k<=right-start+1){
            return helper(nums, k, start, right);
        }
        if(k>=left-start+1)
            return helper(nums, k-(left-start), left, end);
        return nums[right+1];
    }
}

544. Top k Largest Numbers

public class Solution {
    /**
     * @param nums: an integer array
     * @param k: An integer
     * @return: the top k largest numbers in array
     */
    public int[] topk(int[] nums, int k) {
        // write your code here
        int kth = findKthLargest(nums, k, 0, nums.length-1);
        int[] result = new int[k];
        int left=0;
        int right = k-1;
        System.out.println(kth);
        for(int i=0; i<nums.length; i++){
            if(nums[i]>kth){
                result[left] = nums[i];
                left++;
            }
            if(nums[i]==kth&&right>=left){
                result[right] = nums[i];
                right--;
            }
        }
        Arrays.sort(result);
        int start = 0;
        int end = k-1;
        while(start<end){
            int temp = result[start];
            result[start] = result[end];
            result[end] = temp;
            start++;
            end--;
        }
        return result;
    }

    private int findKthLargest(int[] nums, int k, int start, int end){
        if(start>=end)
            return nums[start];
        int mid = start + (end-start)/2;
        int pivot = nums[mid];
        int left = start;
        int right = end;
        while(left<=right){
            while(left<=right && nums[left]>pivot){
                left++;
            }
            while(left<=right && nums[right]<pivot){
                right--;
            }
            if(left<=right){
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                left++;
                right--;
            }
        }
        
        if(start+k-1<=right)
            return findKthLargest(nums, k, start, right);
        if(start+k-1>=left)
            return findKthLargest(nums, k-(left-start), left, end);
        return nums[right+1];
    }
}

// base on heap
class Solution {
    /*
     * @param nums an integer array
     * @param k an integer
     * @return the top k largest numbers in array
     */
     public int[] topk(int[] nums, int k) {
         PriorityQueue<Integer> minheap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
             public int compare(Integer o1, Integer o2) {
                 return o1 - o2;
             }
         });

         for (int i : nums) {
             minheap.add(i);
             if (minheap.size() > k) {
                minheap.poll();
             }
         }

         int[] result = new int[k];
         for (int i = 0; i < result.length; i++) {
             result[k - i - 1] = minheap.poll();
         }
         return result;
    }
};

// base on quicksort
import java.util.Random;

class Solution {
    /*
     * @param nums an integer array
     * @param k an integer
     * @return the top k largest numbers in array
     */
    public int[] topk(int[] nums, int k) {
        // Write your code here
        quickSort(nums, 0, nums.length - 1, k);

        int[] topk = new int[k];
        for (int i = 0; i < k; ++i)
            topk[i] = nums[i];

        return topk;
    }
    
    private void quickSort(int[] A, int start, int end, int k) {
        if (start >= k)
            return;

        if (start >= end) {
            return;
        }
        
        int left = start, right = end;
        // key point 1: pivot is the value, not the index
        Random rand =new Random(end - start + 1);
        int index = rand.nextInt(end - start + 1) + start;
        int pivot = A[index];

        // key point 2: every time you compare left & right, it should be 
        // left <= right not left < right
        while (left <= right) {
            // key point 3: A[left] < pivot not A[left] <= pivot
            while (left <= right && A[left] > pivot) {
                left++;
            }
            // key point 3: A[right] > pivot not A[right] >= pivot
            while (left <= right && A[right] < pivot) {
                right--;
            }

            if (left <= right) {
                int temp = A[left];
                A[left] = A[right];
                A[right] = temp;
                
                left++;
                right--;
            }
        }
        
        quickSort(A, start, right, k);
        quickSort(A, left, end, k);
    }
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容