美文网首页
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