Bootstrap

排序思想-快排

快速排序

912.排序数组 

快速排序核心思想就是每次在当前区间 [left, right] 中选择出一个元素 nums[p],然后将区间内所有大于它的元素和所有小于它的元素都放到其两侧【具体放在哪一侧取决于是升序还是降序】,然后再递归去处理两侧区间。

class Solution {
    public int[] sortArray(int[] nums) {
        quickSort2(nums,0,nums.length-1);
        return nums;
    }
    // 荷兰国旗问题
	public static int first, last;
    public static void quickSort2(int[] arr, int l, int r) {
		if(l>=r) return;
		// 随机这一下,常数时间比较大
		// 但只有这一下随机,才能在概率上把快速排序的时间复杂度收敛到O(n * logn)
		int x = arr[l + (int) (Math.random() * (r - l + 1))];
		partition2(arr, l, r, x);
		// 为了防止底层的递归过程覆盖全局变量
		// 这里用临时变量记录first、last
		int left = first;
		int right = last;
		quickSort2(arr, l, left - 1);
		quickSort2(arr, right + 1, r);
	}

	// 已知arr[l....r]范围上一定有x这个值
	// 划分数组 <x放左边,==x放中间,>x放右边
	// 把全局变量first, last,更新成==x区域的左右边界
	public static void partition2(int[] arr, int l, int r, int x) {
		first = l;
		last = r;
		int i = l;
		while (i <= last) {
			if (arr[i] == x) {
				i++;
			} else if (arr[i] < x) {
				swap(arr, first++, i++);
			} else {
				swap(arr, i, last--);
			}
		}
	}
    public static void swap(int[] nums, int i, int j){
        if(i==j) return;
        nums[i] ^= nums[j];
        nums[j] ^= nums[i];
        nums[i] ^= nums[j];
    }
    
}

双指针交换的方式划分左右区间

215.数组中第K个最大元素.

将大于切分值的元素都放到左侧,小于切分值得元素都放到右侧。因此我们可以使用双指针分别从两端往中间搜索,分别找到左侧小于切分值的元素和右侧大于切分值的元素,交换之,直到两个指针相遇。

对于这道题,我们可以选择区间的中间值作为切分元素,并且我们要事先将切分值交换到区间的右边界:

  1. 避免在划分左右区间的时候,将切分值给覆盖掉。
  2. 最终才可以将切分值放到正确的位置。
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return quickSortKth(nums,k,0,nums.length-1);
    }
    private int quickSortKth(int[] nums, int k, int left, int right){
        int mid =left + (right-left) / 2; 
        swap(nums,mid, right);  // 将切分值放到右边界避免加入元素的划分
        int partition = nums[right], i=left, j=right;  // 双指针从左右边界开始,分别找到要交换的元素
        while(i<j){
            while(i<j && nums[i]>=partition) i++;
            while(j>i && nums[j]<=partition) j--;  // 找到右侧大于切分值的元素【因为是找大于,即使j从right开始,right也不会被选中】
            swap(nums,i,j);
        }
        swap(nums,i,right); // i最后停留的位置一定是右侧首个小于切分值的元素,与切分值交换,则[left, i)都是大于(等于)切分值,[i+1, right]都是小于(等于)切分值

        if(i==k-1) return nums[i];
        if(i<k-1) return quickSortKth(nums,k,i+1,right);
        return quickSortKth(nums,k,left,i-1);

    }
    private void swap(int[] nums, int i, int j){
        if(i == j) return;
        nums[i] ^= nums[j];
        nums[j] ^= nums[i];
        nums[i] ^= nums[j];
    }
}

 

;