代码随想录-数组章节

代码随想录-数组

数组理论基础

704.二分查找

  1. 二分查找算法
    二分查找算法使用前提:有序数组、无重复元素
    循环不变量:注意要先固定好区间之后再考虑while和if中条件的具体操作
    在这里插入图片描述

    二分查找算法可以尝试将O(N)的时间复杂度优化为O(logN)

  2. 暴力解法时间复杂度:O(n)
    二分法时间复杂度:O(logn)

(在判断完nums[mid]后,左右边界应该都不再考虑 nums[mid] 项了。对于左闭右闭区间和左闭右开区间,只是单纯因为区间开闭不同,所以跳过nums[mid]的方式不同)

  1. 自定义标准 [left, right) 写法
    时刻牢记区间为左闭右开。[left, right)

     int left=0;
     int right = nums.length;  //因为是[left,right)区间
    
     while( left < right ){ //因为是[left,right)区间,left==right是不合理情况,所以写left < right
         mid = (left+right)/2;
         if(nums[mid] > target){
             right = mid;   //说明整体区间偏大,右边界right向左收
         } else if (nums[mid] < target){
             left = mid+1;  //说明整体区间偏小,左边界left向右收
         } else return mid;
     }
    
     return -1
    

27.移除元素

  1. 双指针法(快慢指针法)
    快指针走整个循环,慢指针记位置,直接一个定点复制覆盖,元素相对位置不变
    在这里插入图片描述

    在for循环中写if。由于不满足if条件时会跳过if中的操作,会导致快慢指针出现差距,是解题要点。
    通常在if中写普通操作,if的条件用于排除特殊情况

  2. 暴力解法时间复杂度:O(n^2)
    双指针时间复杂度:O(n)

  3. 自定义标准写法

    int slow=0;
    for(int fast=0; fast<nums.length; fast++){
        if(nums[fast]!=val){    //只有满足if中的条件时,fast指针和slow指针都往前走。不满足if中的条件时,跳过if中的操作,导致fast和slow出现差距
            nums[slow++]=nums[fast];
        }
    }
    
    return slow;    //此时slow经过++操作正好等于新数组长度,返回新数组长度
    

977.有序数组的平方

  1. 双指针法(对撞指针)
    对撞指针。有序数组的有序操作都可以考虑一下双指针
    在这里插入图片描述

  2. 时间复杂度:O(N)

  3. 自定义标准写法

    for(int i=0, j=nums.length-1; i<=j; ){ //i<=j是因为要考虑到最后i和j同时指向的那个元素
        //对撞过程,满足条件的就移动
    }
    
    

209.长度最小的子数组

  1. 双指针法(滑动窗口)
    作为窗口右边的指针正常循环,每次往后走一个。窗口左边的指针在一次循环内部做while循环判断

    有效降低时间复杂度为O(2N)。因为数组中每个数只需要经历进入窗口和出窗口两个操作

  2. 暴力解法时间复杂度:O(n^2)
    滑动窗口时间复杂度:O(n)

  3. 自定义标准写法
    三元运算符:条件表达式 ? 表达式1 : 表达式2
    问号前面的位置是判断的条件,判断结果为bool型,为true时调用表达式1,为false时调用表达式2。

    for(int left=0, right=0; right < nums.length; right++){
        sum += nums[right]; //计算条件
        while (sum >= s) {
            result = Math.min(result, right - left + 1); //运算并记录当前情况
            sum -= nums[left++]; //最后左指针右移,试图缩小窗口
        }
    }
    return (result == Integer.MAX_VALUE) ? 0 : result;
    

59.螺旋矩阵2

  1. 思路:
    2. 确定循环条件是什么(这里最外层循环是按圈计数的)
    3. 确定下每次循环中会改变的量(这里每一圈的起始位置[startx][starty]
    4. 确定内层循环不变条件(这里指每一条边的循环方式,都是包括头不包括尾)
    在这里插入图片描述

    循环不变量:要确定在循环过程中始终不变的循环条件,要有统一的规则,例如如何操作这四个边。
    对于复杂的循环,可以边写边声明变量

58.区间和

在这里插入图片描述

使用暴力解的话,如果查询m次的话,算法时间复杂度为 O(n * m) m

  1. 前缀和法:在涉及计算区间和的问题时非常有用!
    前缀和的思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数。在这里插入图片描述

  2. 自定义标准写法

     import java.util.Scanner;
    
     public class Main {
         public static void main(String[] args) {
             Scanner scanner = new Scanner(System.in);
    
             int n = scanner.nextInt();
             int[] vec = new int[n];
             int[] p = new int[n];
    
             int presum = 0;
             for (int i = 0; i < n; i++) {
                 vec[i] = scanner.nextInt();
                 presum += vec[i];
                 p[i] = presum;
             }
    
             while (scanner.hasNextInt()) {
                 int a = scanner.nextInt();
                 int b = scanner.nextInt();
    
                 int sum;
                 if (a == 0) { sum = p[b]; } 
                 else { sum = p[b] - p[a - 1]; }
                 System.out.println(sum);
             }
             scanner.close();
         }
     }
    

44.开发商购买土地

附录

  1. 二分查找法 [left, right] 写法
    时刻牢记区间定义为左闭右闭
     int left=0;
     int right=nums.length-1; //因为是【left,right】区间,right需要从有意义的数组开始
    
     while( left <= right ){ //因为是【left,right】区间,left==right是合理情况需要考虑,所以写left<=right
         middle=(left+right)/2;
         if(target < nums[middle]){
             right=middle-1; //因为是【left,right】区间,当target已经确认位于nums数组的左半侧且小于此时的nums[middle]时,直接令right=middle-1,排除nums[middle]。
         } else if (target > nums[middle]){
             left=middle+1;  //因为是【left,right】区间,当target已经确认位于nums数组的右半侧且大于此时的nums[middle]时,直接令left=middle+1,排除nums[middle]。
         } else return middle;
     }
     return -1
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值