美文网首页
3. 双指针-quick sort+quick select

3. 双指针-quick sort+quick select

作者: 谢谢水果 | 来源:发表于2018-12-13 03:02 被阅读0次

    思想:

    使左右整体有序 找到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);
        }
    };
    

    相关文章

      网友评论

          本文标题:3. 双指针-quick sort+quick select

          本文链接:https://www.haomeiwen.com/subject/flwmhqtx.html