算法:数组题目总结

数组思维导图总结:
在这里插入图片描述

有序数组才可用二分法
解决此题目需注意搜索区间,如数组的左闭右闭区间和左闭右开区间对应的搜索区间是不同的。

题目1:704. 二分查找

class Solution {

    public int search(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        //如果是左闭右闭区间
        while(left<=right){
            int middle=(left+right)/2;
            //二分法就是比较middle的值是否大于、小于、等于target
            if(nums[middle]>target){
                //搜索区间变动 此时middle已经比较过了因为是左闭右闭区间
                right=middle-1;
            }else if(nums[middle]<target){
                left=middle+1;
            }else{
                return middle;
            }
        }
        return -1;
    }
}

题目2:35. 搜索插入位置
注意:卡在返回值了right+1了,二刷需注意这四种情况,把right+1换成left也可,因为left<=right的循环到最后一次会符合nums[middle]<target条件将left进行+1,所以left就是元素要插入的位置

class Solution {

    public int searchInsert(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        while(left<=right){
          int middle=(left+right)/2;
            if(nums[middle]>target){
                right=middle-1;
            }else if(nums[middle]<target){
                left=middle+1;
            }else{
                return middle;
            }
        }
        // 分别处理如下四种情况
        // 目标值在数组所有元素之前  [0, -1] -1不返回
        // 目标值等于数组中某一个元素  return middle;
        // 目标值插入数组中的位置 [left, right],return  right + 1/left
        // 目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return right + 1/left
        return right+1;
        
    }
}

题目3: 34. 在排序数组中查找元素的第一个和最后一个位置
思路:通过二分法找到target值,通过循环找到最左侧和最右侧的值
注意:当找到target值时,要通过便历找到最左侧和最右侧的值,二刷时需注意

class Solution {

    public int[] searchRange(int[] nums, int target) {
        if(nums.length==0){
            return new int[]{-1,-1};
        }
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int middle=(left+right)/2;
            if(nums[middle]>target){
                right=middle-1;
            }else if(nums[middle]<target){
                left=middle+1;
            }else {
                int middleLeft=middle;
                int middleRight=middle;
                //边界条件容易出错
                while(middleLeft-1>=0&&nums[middle]==nums[middleLeft-1]){
                    middleLeft--;
                }
                //边界条件容易出错
                while(middleRight+1<nums.length &&nums[middle]==nums[middleRight+1]){
                    middleRight++;
                }   
                return new int[]{middleLeft,middleRight};        
            }
        }
       return new int[]{-1,-1};
    }
}

题目4: 27. 移除元素
1)暴力解法 时间复杂度:O(n^2) 空间复杂度:O(1)
注意:忘记将下标和数组最右侧下标缩减导致没ac

class Solution {
    public int removeElement(int[] nums, int val) {
        int size=nums.length;
        for(int i=0;i<=size-1;i++){
            if(nums[i]==val){
                for(int j=i;j<size-1;j++){
                     nums[j]=nums[j+1];
                }
                //因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                i--;
                //数组也缩减一位
                size--;
            }
        }
        return size;
    }
}

2)双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。慢指针指的是新数组中的值。时间复杂度:O(n) 空间复杂度:O(1)
注意:完全没get到这个点,看了视频才理解慢指针是指新数组中的值,所以当快指针不等于目标值时要更新新数组

class Solution {
    public int removeElement(int[] nums, int val) {
        //新数组中的下标
        int show=0;
        for(int fast=0;fast<nums.length;fast++){
            //当快指针不等于目标值时,将快指针的值赋值给新数组
            if(nums[fast]!=val){
                nums[show]=nums[fast];
                show++;
            }
        }
        return show;
    }
}

题目5: 977.有序数组的平方
1)暴力解法 时间复杂度:O(n + nlogn)

class Solution {

    public int[] sortedSquares(int[] nums) {
        //平方
        for(int i=0;i<nums.length;i++){
            nums[i]=nums[i] * nums[i];
        }
        //排序
        Arrays.sort(nums);
        return nums;
    }
}

2)双指针法
注意:创建新数组 因为边界问题没ac

class Solution {

    public int[] sortedSquares(int[] nums) {
        int left=0;
        int right=nums.length-1;
        int[] result=new int[nums.length];
        int k=result.length-1;
        while(left<=right){
            if(nums[right] * nums[right]>nums[left] * nums[left]){
                 result[k]=nums[right] * nums[right];
                 right--;
                 k--;
            }else{
                result[k]=nums[left] * nums[left];
                left++;
                k--;
            }
        }
        return result;
    }
}

题目6:209.长度最小的子数组
1)暴力解法:在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程 。时间复杂度:O(n^2)
注意:子序列长度为end-start+1,每次收集子序列要把sum置为0

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result=Integer.MAX_VALUE;
        //start为子序列的起始位置
        for(int start=0;start<nums.length;start++){
           int sum = 0;
            //end为子序列的终止位置
            for(int end=start;end<nums.length;end++){
                sum+=nums[end];
                if(sum>=target){
                    result= Math.min(end-start+1,result);
                    break;
                }
            }
        }
        return result==Integer.MAX_VALUE?0:result;
    }
}

2)滑动窗口:如何用一个for循环来解决问题。
注意:如果用一个for循环索引应表示终止位置。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result=Integer.MAX_VALUE;
        //start为子序列的起始位置
        int start=0;
        int sum = 0;
        //end为子序列的终止位置
        for(int end=start;end<nums.length;end++){
            sum+=nums[end];
            //用while是为了防止给定数组中每一个子序列的和都大于target的情况,一直取到最小的子序列
            while(sum>=target){
                result= Math.min(end-start+1,result);
                //起始位置做变动
                sum-=nums[start];
                start++;
            }
        }
        return result==Integer.MAX_VALUE?0:result;
    }
}

题目7:59. 螺旋矩阵 II
注意:模拟转圈循环遍历上右下左的下标位置,转圈到最后剩一个值的时候(判断为奇数的时候)直接赋值就好了

class Solution {

    public int[][] generateMatrix(int n) {
        //二维数组
        int[][] res = new int[n][n];
        //控制循环次数
        int size=0;
        //startX ,startY表示每一圈的起始位置 要跟着变动
        int startX=0;
        int startY=0;
        //index表示每一圈要缩减的最后位置
        int index=1;
        //count表示转圈的每一个数
        int count=1;
        int x,y;
        //转n/2圈
        while(size++<n/2){
            //区间为左闭右开
            //上层
            for(y=startY;y<n-index;y++){
                res[startX][y]=count++;
            }
            //右层
            for(x=startX;x<n-index;x++){
                res[x][y]=count++;
            }
            //下层
            for(;y>startY;y--){
                res[x][y]=count++;
            }
            //左层
            for(;x>startX;x--){
                res[x][y]=count++;
            }
            //下一圈
            startX++;
            startY++;
            index++;
        }
        if (n % 2 == 1) {
            res[startX][startY] = count;
        }
        return res;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值