数组--基础算法思路的应用

例题:颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

注意: 不能使用代码库中的排序函数来解决这道题。

首先,最简单的思路是使用计数排序,因为只有三个元素。
其次,可以使用三路快排思想。维护三个指针 zeroitwo,让它们满足:

arr[0...zero] == 0,arr[zero+1...i-1] == 1,arr[two...n-1] == 2

使用i遍历数组,当nums[i]:

  • ==1,i++
  • ==0,swap(nums[i],nums[++zero]) , i++
  • ==2,swap(nums[i],nums[–tow])

当i = two的时候停止。
代码如下:

class Solution {
    public void sortColors(int[] nums) {
        int zero = -1;
        int two = nums.length;
        for(int i=0;i<two;){
            if(nums[i]==0){
                swap(nums,i,++zero);
                i++;
            }else if(nums[i]==1){
                i++;
            }else{
                swap(nums,i,--two);
            }
        }
    }
    public void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}
1.合并两个有序数组(归并思想)

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 num1 成为一个有序数组。
说明:
·初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
·你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素

归并排序的思想中,就是两个有序数组进行合并,这里则更加简单。不过既然是放在nums1中,而不是新建一个数组,那么就要从m-1和n-1分别向前遍历,然后从nums1的m+n-1处向前存储。
时间复杂度:O(m+n)

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        //从后向前遍历可以避免使用额外空间
        int p = m + n -1;
        int p1 = m -1;
        int p2 = n -1;
        while(p1>=0 && p2>=0){
            if(nums1[p1]>nums2[p2]){
                nums1[p--] = nums1[p1--];
            }else{
                nums1[p--] = nums2[p2--];
            }
        }
        while(p2>=0){
            nums1[p--] = nums2[p2--];
        }
    }
}
2.数组中的第K个最大元素(快排思想)

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

之前做过这个题,不过当时用的是优先队列。现在使用快排思想,快排就是使一个元素快速到达它在排序数组中的正确位置。那么这个题的做法就是:

  1. 如果l==nums.length-k,那么此时nums[x]就是要找的值;
  2. 如果l<nums.length-k,那么说明第k个最大元素在x右边,在右边继续快排;
  3. 如果l>nums.length-k,那么说明第k个最大元素在x左边,在左边继续快排。
class Solution {
    int res;
    public int findKthLargest(int[] nums, int k) {
        findK(nums,0,nums.length-1,k);
        return res;
    }
    public void findK(int[] nums,int left,int right,int k){
        int l = left;
        int r = right;
        if(l==r) res = nums[l];
        if(l<r){
            int x = nums[left];
            while(l<r){
                while(l<r && nums[r]>x){
                    r--;
                }
                if(l<r){
                    nums[l] = nums[r];
                    l++;
                }
                while(l<r && nums[l]<x){
                    l++;
                }
                if(l<r){
                    nums[r] = nums[l];
                    r--;
                }
            }
            System.out.println("");
            if(l==nums.length-k) res = x;
            if(l<nums.length-k)  findK(nums,l+1,right,k);
            if(l>nums.length-k)  findK(nums,left,l-1,k);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值