前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >详解数组刷题上

详解数组刷题上

作者头像
公众号guangcity
发布2019-09-20 16:22:06
6020
发布2019-09-20 16:22:06
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)

详解数组刷题上

本专题内容如下:

一、初始定义及原地修改1.283. 移动零2.27. 移除元素3.26. 删除排序数组中的重复项4.80. 删除排序数组中的重复项 II二、基础思想应用1.75. 颜色分类2.88. 合并两个有序数组3.215. 数组中的第K个最大元素4.167. 两数之和 II - 输入有序数组5.209. 长度最小的子数组

一、初始定义及原地修改

类似题目:

  • 283. 移动零
  • 27. 移除元素
  • 26. 删除排序数组中的重复项

注意的问题

  • 如何定义变量?
  • 如何从数组中删除?
  • 剩余元素的排列是否要保证原有的相对顺序?
  • 是否有空间复杂度的要求? O(1)
1.283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

代码语言:javascript
复制
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。

实现思路:

  • 拿出非0元素
  • 将非0元素拿出来,然后空位补0

实现:

循环一次找出不为0的index,并将该Index对应的值依次存储到数组中,后面的全部为0即可!

代码语言:javascript
复制
class Solution {
    public void moveZeroes(int[] nums) {
        int j=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[j++]=nums[i];
            }
        }
        //剩余位置放0
        while(j<nums.length){
            nums[j++]=0;
        }
    }
}
2.27. 移除元素

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

代码语言:javascript
复制
给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

你不需要考虑数组中超出新长度后面的元素。

实现思路:

找到不等目标值的元素,然后利用不等目标值的个数原地修改数组。

实现:

代码语言:javascript
复制
class Solution {
    public int removeElement(int[] nums, int val) {
        int i,j=0;
        for(i=0;i<nums.length;i++){
            if(nums[i]!=val){
                nums[j++]=nums[i];
            }
        }
        return j;
    }
}
3.26. 删除排序数组中的重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

代码语言:javascript
复制
给定数组 nums = [1,1,2], 

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 

你不需要考虑数组中超出新长度后面的元素。

实现思路:

找到当前元素与前一元素不等的位置,开始原地修改数组。

实现:

代码语言:javascript
复制
class Solution {
    public int removeDuplicates(int[] nums) {
        int i=1,j=0;

        while(i<nums.length){
            if (nums[i]!=nums[i-1]){
                nums[++j]=nums[i];
            }
            i++;
        }
        return j+1;
    }
}
4.80. 删除排序数组中的重复项 II

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

代码语言:javascript
复制
给定 nums = [1,1,1,2,2,3],

函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。

你不需要考虑数组中超出新长度后面的元素。

实现思路:

代码语言:javascript
复制
1   2
cur back
1   2   2
pre cur back

当数组中的某一部分满足上述两者之一的时候,就可以移动cur(cur记录的就是该数组的实际大小)。

实现:

代码语言:javascript
复制
class Solution {
    public int removeDuplicates(int[] nums) {
        int cur,pre,back;
        cur=1;
        pre=cur-1;
        back=cur+1;
        while(back<nums.length){
            if(nums[cur]!=nums[back]||(nums[cur]==nums[back] && nums[cur]!=nums[pre])){
                pre=cur;
                nums[cur+1]=nums[back];
                cur++;
            }
            back++;
        }
        return cur+1;
    }
}

前面两个元素不修改,直到到第3个元素,也就是index=2开始比较。使用j来存储满足题意的位置,让nums[i]与nums[j-2]比较,然后赋值即可。

代码语言:javascript
复制
class Solution {
    public int removeDuplicates(int[] nums) {
        int i=2,j=2;
        while(i<nums.length){
            if(nums[i]>nums[j-2]){ //这里一定是j-2而不是i-2,如果是i-2会在下面一行代码执行过程中将原来的值覆盖掉,此时结果就不对了,而如果是j-2,就是正确的,因为j中存放的就是未覆盖的值,如果所有元素都是不一样的,那么i与j的指向一致,而当元素并不一样的时候,j-2中就存放了i-2实际元素!
                nums[j++]=nums[i];
            }
            i++;
        }
        return j;
    }
}

二、基础思想应用

基本思想:

  • 快速排序
  • 三路快排
  • 二分查找
  • 基数排序

类似题目:

  • 75. 颜色分类
  • 88. 合并两个有序数组
  • 215. 数组中的第K个最大元素
  • 167. 两数之和 II - 输入有序数组
  • 209. 长度最小的子数组

二分查找法模板:

代码语言:javascript
复制
int l = 0, r = n-1; // 在[l...r]的范围里寻找target:前闭后闭
while( l <= r ){    // 只要还有可以查找的内容。当 l == r时,区间[l...r]依然是有效的
    int mid = l + (r-l)/2;
    if( arr[mid] == target ) 
        return mid;
    //mid已经判断过了
    if( target > arr[mid] )
        l = mid + 1;  // target在[mid+1...r]中; [l...mid]一定没有target
    else    // target < arr[mid]
        r = mid - 1;  // target在[l...mid-1]中; [mid...r]一定没有target
}

注意的问题

  • 求mid值是采用(l+r)/2容易整形溢出
  • 采用mid = l + (r-l)/2;
1.75. 颜色分类

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

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

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

示例:

代码语言:javascript
复制
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]

实现思路:

统计一次红、白、黑的数量,然后再循环一次原地修改!

实现:

代码语言:javascript
复制
class Solution {
    public void sortColors(int[] nums) {
        int red=0,white=0,blue=0;
        for(int i=0;i<nums.length;i++){
            switch (nums[i]){
                case 0:
                    red++;
                    break;
                case 1:
                    white++;
                    break;
                default:
                    blue++;
            }
        }
        for(int i=0;i<nums.length;i++){    
            if (i<red){
                nums[i]=0;
            }else if(i<red+white){
                nums[i]=1;
            }else{
                nums[i]=2;
            }
        }
    }
}

三路快排

代码语言:javascript
复制
class Solution {
    public void sortColors(int[] nums) {
        int red_white = -1;
        int white_blue= nums.length;
        int i=0;
        int temp;
        while(i<white_blue){
            if(nums[i]==0){
                red_white++;
                temp=nums[red_white];
                nums[red_white]=nums[i];
                nums[i]=temp;
                i++;
            }else if(nums[i]==2){
                white_blue--;
                temp=nums[white_blue];
                nums[white_blue]=nums[i];
                nums[i]=temp;
            }else{
                i++;
            }
        }
    }
}
2.88. 合并两个有序数组

给定两个有序整数数组 nums1nums2,将 nums2 合并到 nums1使得 num1 成为一个有序数组。

说明:

  • 初始化 nums1nums2 的元素数量分别为 mn
  • 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:

代码语言:javascript
复制
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]

实现思路:

从后往前遍历,然后去比较两数组大小,谁大先放谁。

实现:

代码语言:javascript
复制
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int n1=m-1,n2=n-1;

        for(int i=m+n-1;i>=0;i--){
            if((n1>=0 && n2>=0 && nums1[n1]>=nums2[n2]) || (n2<0 && n1>=0)){
                nums1[i]=nums1[n1];
                n1--;
            }else if((n1>=0 && n2>=0 && nums1[n1]<nums2[n2]) || (n1<0 && n2>=0)){
                nums1[i]=nums2[n2];
                n2--;
            }
        }
    }
}
3.215. 数组中的第K个最大元素

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

示例 1:

代码语言:javascript
复制
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

代码语言:javascript
复制
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

实现思路:

直接使用冒泡排序,当冒出k次后,此时的元素就是第K个最大元素。

实现:

代码语言:javascript
复制
class Solution {
    public int findKthLargest(int[] nums, int k) {
        int i,j;
        int n=nums.length;
        int temp;
        for (i=0;i<n-1;i++){
            for (j=i+1;j<n;j++){
                if (nums[i]<nums[j]) {
                    temp=nums[i];
                    nums[i]=nums[j];
                    nums[j]=temp;
                }
            }    
            k--;
            if(k==0){
                break;
            }
        }
        return nums[i]; 
    }


}

交换多次快排

代码语言:javascript
复制
class Solution {
    public int findKthLargest(int[] nums, int k) {
        quickSort(nums,0,nums.length-1);
        return nums[k-1]; 
    }
    public void quickSort(int[] nums,int left,int right){
        if(left>right){
            return;
        }
        int pivot = nums[left];
        int i = left;
        int j = right;
        int temp;
        while(i<j){
            while(i<j && nums[j]<=pivot)
                j--;

            if(i<j){
                temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
            while(i<j && nums[i]>=pivot)
                i++;
            if (i<j){
                temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
        }
           //nums[left]=nums[i]; 这种方法这行不能要!
        nums[i]=pivot;
        quickSort(nums,left,i-1);
        quickSort(nums,i+1,right);
    }

}

最后交换快排

代码语言:javascript
复制
class Solution {
    public int findKthLargest(int[] nums, int k) {
        quickSort(nums,0,nums.length-1);
        return nums[k-1]; 
    }
    public void quickSort(int[] nums,int left,int right){
        if(left>right){
            return;
        }
        int pivot = nums[left];
        int i = left;
        int j = right;
        int temp;
        while(i<j){
            while(i<j && nums[j]<=pivot)
                j--;
            while(i<j && nums[i]>=pivot)
                i++;
            if (i<j){
                temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
        }
        nums[left]=nums[i]; //必须要!
        nums[i]=pivot;
        quickSort(nums,left,i-1);
        quickSort(nums,i+1,right);
    }

}
4.167. 两数之和 II - 输入有序数组

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2

说明:

  • 返回的下标值(index1 和 index2)不是从零开始的。
  • 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

示例:

代码语言:javascript
复制
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

实现思路:

二分查找法

实现:

注意二分查找的代码中左右可以相等!

代码语言:javascript
复制
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] res=new int[2];

        for(int i=0;i<numbers.length;i++){
            int second = binarySearch(numbers, i+1, numbers.length-1, target-numbers[i]);
            if(second>-1){
                res[0]=i+1;
                res[1]=second+1;
            }
        }
        return res;

    }
    public int binarySearch(int[] numbers, int start, int end, int target){
        int i=start;
        int j=end;
        while(i<=j){
            int mid=(i+j)/2;
            if(numbers[mid]== target){
                return mid;
            }else if(numbers[mid]> target){
                j=mid-1;
            }else{
                i=mid+1;
            }
        }
        return -1;
    }
}
5.209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和≥ s 的长度最小的连续子数组如果不存在符合条件的连续子数组,返回 0。

示例:

代码语言:javascript
复制
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。

进阶:

如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

实现思路:

循环+二分

实现:

注意二分查找的代码中左右可以相等!

时间复杂度:O(nlogn),空间复杂度O(n)。

思路:

将原先数组所有数字累加求和得到一个新数组,例如:

代码语言:javascript
复制
nums=[2,3,1,2,4,3]
parNums=[0,2,5,6,8,12,15]

然后循环parNums,对每一个数组中的index对应的值,利用二分法找到最小的窗口。

举个例子:

代码语言:javascript
复制
nums=[2,3,1,2,4,3]
parNums=[0,2,5,6,8,12,15]
--------------
i=0时
--------------
第一轮
left=0,right=6
left<right,计算出mid=3,此时对应的值为6,mid距离i的和也就是6<7,
调整left=mid+1=4。
第二轮
left=4,right=6
left<right,计算出mid=5,此时对应的值为12,mid距离i的和也就是12>7,
调整right=mid-1。
是不是上述可以看作是查找7的二分法,那么后面依次类推即可。
当然left调整也可以是left++,right调整也可以是right--,也可以AC,但是效率会低一些!
--------------
......

循环+二分

代码语言:javascript
复制
public class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int[] parNums = new int[nums.length+1];
        for(int i=1;i<parNums.length;i++){
            parNums[i]=parNums[i-1]+nums[i-1];
        }

        int min=0;
        for(int i=0;i<parNums.length;i++){
            int left=i;
            int right=parNums.length-1;
            while(left<=right){
                int mid=left+(right-left)/2;
                int subSum=parNums[mid]-parNums[i];
                if(subSum>=s){
                    right=mid-1; //可以换成right--;
                    min=min==0?mid-i:Math.min(min,mid-i);
                }else{
                    left=mid+1; //可以换成left++;
                }
            }
        }
        return min;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 详解数组刷题上
  • 一、初始定义及原地修改
    • 1.283. 移动零
      • 2.27. 移除元素
        • 3.26. 删除排序数组中的重复项
          • 4.80. 删除排序数组中的重复项 II
          • 二、基础思想应用
            • 1.75. 颜色分类
              • 2.88. 合并两个有序数组
                • 3.215. 数组中的第K个最大元素
                  • 4.167. 两数之和 II - 输入有序数组
                    • 5.209. 长度最小的子数组
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档