leetcode 快速排序相关

leetcode 快速排序相关

荷兰国旗问题 leetcode 75

荷兰国旗问题便于理解快速排序中的partition过程,荷兰国旗问题,给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。将颜色按照0、1、2来表示,问题可以转化为将数组中的元素按照小于1、等于1和大于1的顺序排列。
思路:使用两个指针分别记录小于位置和大于的位置,遍历数组,遇到小于pivot的数就将其与小于位置的下一个位置调换,遇到等于的数就直接跳过,遇到大于pivot的数就将其与大于位置的前一个数交换位置。

class Solution {
    public void sortColors(int[] nums) {
        if (nums == null || nums.length == 0) return;
        int target = 1;
        int less = -1;
        int more = nums.length;
        for (int i = 0; i < nums.length && i < more; i++) {
            if (nums[i] < target) {
                less++;
                swap(nums, i, less);
            }else if (nums[i] > target) {
                more--;
                swap(nums, i, more);
                i--;
            }else {
                continue;
            }
        }
    }

    public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

快速排序 leetcode 912

完成荷兰国旗问题后,就可以引出快速排序问题。快速排序的基本思路为,将数组中最后一个数选定为pivot,将数组中第一个数到倒数第二个数之间的数组划分为小于pivot、等于pivot和大于pivot的部分,接着将数组最后一个数与记录大于部分位置的那个数调换位置,至此0~less为小于pivot的数(less记录小于位置), less+1到more为等于pivot的数,more+1到数组最后为大于pivot的数。然后,在对小于部分,和大于部分继续做partition过程直到所有数排序完成。

public class Solution {
	public void sort(int nums) {
		quickSort(nums, 0, nums.length-1);
	}
	public void quickSort(int[] nums, int L, int R) {
		if (nums == null || nums.length < 2) return;
		int[] p = partition(nums, L, R);
		quickSort(nums, L, p[0]-1);
		quickSort(nums, p[1]+1, R);
	}
	public int[] partition(int[] nums, int L, int R) {
		if (L <= R) {
			// 快排3.0 对数组进行打乱处理,避免最坏情况的时间复杂度O(N^2)
			int ranIndex = L + (int)(Math.random()*(R-L+1));
			swap(nums, ranIndex, R);
			int less = L-1, more = R;
			int pivot = nums[R];
			for (int i = L; i < more; i++) {
				if (nums[i] < pivot) {
					less++;
					swap(nums, i, less);
				}else if (nums[i] > pivot) {
					more--;
					swap(nums, i, more);
					i--;
				}else {
					continue;
				}
			}
			swap(nums, more, R);
			return new int[]{less+1, more};
		}
	}
}

leetcode K个最大元素 leetcode 215

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
该问题我认为比较好的解决方案是使用堆,但是为了加深对快排的理解,在这里使用快速排序选择的方式。
思路:在数组中随机选一个数作为pivot,将数组划分为大于等于小于三部分。之后,判断等于部分的最后一个数的位置是否恰好等于数组长度减k,若是则说明该数恰好为第k大的元素,若小于k则说明第k大的数在数组右边部分,对右边部分进行快速排序选择,若大于k则说明第k大的数在数组左侧,对左侧进行快速排序选择。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null || nums.length < k) return -1;
        return partition(nums, 0, nums.length-1, k);
    }

    public int partition(int[] nums, int L, int R, int k) {
        if (L <= R) {
            int ranIndex = L + (int)(Math.random*(R-L+1));
            swap(nums, ranIndex, R);
            int less = L-1, more = R;
            int pivot = nums[R];
            for (int i = L; i < more; i++) {
				if (nums[i] < pivot) {
					less++;
					swap(nums, i, less);
				}else if (nums[i] > pivot) {
					more--;
					swap(nums, i, more);
					i--;
				}else {
					continue;
				}
			}
			swap(nums, more, R);
			if (more == nums.length-k) return nums[more];
			else if (more < nums.length-k) partiotion(nums, more+1, R);
			else if (more > nums.length-k) partition(nums, L, more-1);
			return nums[nums.length-k];
        }
        return -1;
    }

    public static void swap(int [] arr, int p1, int p2) {
		int temp = 0;
		temp = arr[p1];
		arr[p1] = arr[p2];
		arr[p2] = temp;
	}
}

leetcode K个最小元素 leetcode 40

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

这道题思路与上述第k个最大值的思路基本相同。同样较好的结局方式是使用堆,这里使用快速选择排序的方法。
思路:随机选择数组中的一个数作为pivot,将数组划分为小于等于大于三部分,检查等于部分的第一个值,也就是less+1位置是否恰好等于k-1,若相等则说明从第一个数到less+1位置上的数就是k个最小元素,若小于k-1则说明k个最小元素在右边,若大于则说明k个最小元素在左边。

class Solution {
    public int[] getLeastNumbers(int[] arr,int k) {
		if(arr.length==0 || k==0) {
			return new int[0];
		}
		//数组下标范围是0~length-1,枢纽元素下标是k-1
		int[] nums = QuickSort(0,arr.length-1,arr,k-1);
		return nums;
	}
	
	private int[] QuickSort(int left,int right,int[] arr,int k) {
		int position = partition(left,right,arr);
		//输入的是k=k-1,因此此处返回的是(k-1)+1个长度
		if(position==k) return Arrays.copyOf(arr, k+1);
		return position<k? QuickSort(position+1, right, arr,k):QuickSort(left, position-1, arr,k);
	}

    private int partition(int L, int R, int[] arr) {
        int random = L + (int)Math.random()*(R-L+1);
        swap(arr, random, R);
        int pivot = arr[R];
        int less = L-1, more = R;
        for (int i = L; i < arr.length && i < more; i++) {
            if (arr[i] <= pivot) {
                less++;
                swap(arr, i, less);
            }else if (arr[i] > pivot) {
                more--;
                swap(arr,i,more);
                i--;
            }
        }
        swap(arr, more, R);
        return less+1;
    }

    public void swap(int [] arr, int p1, int p2) {
		int temp = 0;
		temp = arr[p1];
		arr[p1] = arr[p2];
		arr[p2] = temp;
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值