玩转算法(三)——数组(高级排序算法的运用)

快速排序的运用

75. 颜色分类(中等)

75. 颜色分类

思路一:先遍历数组,计算0,1,2的个数,再分别顺序写入数组。

思路二:采用三路快排的思想。

public void sortColors(int[] nums) {
	int zero = -1;
	int two = nums.length;
	
	for(int i = 0; i < two; ) {
		if(nums[i] == 1)
			i++;
		else if(nums[i] == 0) {
			zero++;
			swap(nums, zero, i);
			i++;
		}else if(nums[i] == 2) {
			two--;
			swap(nums, two, i);
		}
	}
	
}

public static void swap(int [] a,int x,int y){
    int temp;
    temp=a[x];
    a[x]=a[y];
    a[y]=temp;
}

215. 数组中的第K个最大元素(中等)

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

思路一:先排序,时间复杂度为O(NlogN)

思路二:采用优先队列,时间复杂度为O(NlogK)

思路二:采用双路快排,时间复杂度为O(N)

public int findKthLargest(int[] nums, int k) {
	return findKthLargest(nums, 0, nums.length-1, nums.length+1-k);
}

public static int findKthLargest(int[] nums, int left, int right, int k) {
	if(left < right) {
		int number = partition(nums, left, right);
 	if(number + 1 == k) 
 		return nums[number];
 	else if(number + 1 > k) 
 		return findKthLargest(nums, left, number-1, k);
 	else
 		return findKthLargest(nums, number+1, right, k);
	}
	else
		return nums[left];
	
}
  
public static int partition(int[] nums, int left, int right) {
	int n = nums[left];
	int i = left+1, j = right;
	while(true) {
		while(i <= j && nums[i] < n)
			i++;
		while(j >= left + 1 && nums[j] > n)
			j--;
		
        if( i > j )
            break;
              
		swap(nums, i, j);
		i++;
		j--;
	}
	swap(nums, i-1, left);
	return i-1;
}

public static void swap(int [] a,int x,int y){
    int temp;
    temp=a[x];
    a[x]=a[y];
    a[y]=temp;
}

归并排序的运用

88. 合并两个有序数组(简单)

88. 合并两个有序数组

思路一:归并的思想,要开辟新数组,从前往后遍历。

public void merge(int[] nums1, int m, int[] nums2, int n) {
	int[] nums3 = new int[m];
	for(int i = 0; i<m; i++) {
		nums3[i] = nums1[i];
	}
	
	int i = 0,j = 0,k = 0;
	while(i < m && j < n) {
		if(nums3[i] < nums2[j]) {
			nums1[k++] = nums3[i++];
		}else{
			nums1[k++] = nums2[j++];
		}
	}
	while(i < m) 
nums1[k++] = nums3[i++];
	while(j < n) 
nums1[k++] = nums2[j++];
}

思路二:从后往前遍历,则不需要开辟新的数组。

public void merge2(int[] nums1, int m, int[] nums2, int n) {
    int len1 = m - 1;
    int len2 = n - 1;
    int len = m + n - 1;
    while(len1 >= 0 && len2 >= 0) {
        // 注意--符号在后面,表示先进行计算再减1,这种缩写缩短了代码
        nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--];
    }
    // 表示将nums2数组从下标0位置开始,拷贝到nums1数组中,从下标0位置开始,长度为len2+1
    System.arraycopy(nums2, 0, nums1, 0, len2 + 1);
}

还有个从后向前的应用,就是数组后移,需要从后向前遍历。

堆排序的运用

347. 前 K 个高频元素(中等)

347. 前 K 个高频元素

public int[] topKFrequent(int[] nums, int k) {
    TreeMap<Integer, Integer> map = new TreeMap<>();
    for(int num: nums){
        if(map.containsKey(num))
            map.put(num, map.get(num) + 1);
        else
            map.put(num, 1);
    }

    PriorityQueue<Integer> pq = new PriorityQueue<>(
            (a, b) -> map.get(a) - map.get(b)
        );
    
    for(int key: map.keySet()){
        if(pq.size() < k)
            pq.add(key);
        else if(map.get(key) > map.get(pq.peek())){
            pq.remove();
            pq.add(key);
        }
    }
    int[] num = new int[k];
    int i = 0;
    while(!pq.isEmpty()){
        num[i] = pq.remove();
        i++;
    }
             
    return num;
}

比较器的解释说明:父节点索引为K,子节点索引为J,最小堆则data[K] < data[J]。

进行shift down时,判断 if(data.get(k).compareTo(data.get(j)) <= 0 ),则break,不进行任何操作。

所以比较器需要 data[K] < data[J] ,return -1; 才行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值