汇聚|LeetCode 数组篇(上)

ps:本篇内容是基于LeetCode题目进行分类总结而出的一些个人经验,希望对你有帮助!

关于子数组的那些事!

简介:给定一个数组,围绕着子数组进行展开!
核心:子数组一定是连续的,子数组一定是连续的,子数组一定是连续的!

子数组的最值——和积

  如果题目是围绕子数组的最大和,积等展开的,那很大的概率是要用到++局部迭代++和++全程更新++(名字是我瞎起的)。
   此外,你要明确你在干什么,即在遍历过程中,你以什么做为出发点,如以当前元素作为最佳子数组的结束元素……(结合后面的代码你会理解的)
  先送你上述两把菜刀,方便你更好的去切下面的菜!
image.png

  • 局部迭代
简介:在遍历数组的过程中,对满足一定条件的元素连接起来,如果不满足就另起门户!
形式:
for(int i=0;i<nums.length;i++){
 变量=条件函数(变量与nums[i],nums[i])
// 如:nums[i]=Math.max(nums[i]+nums[i-1],nums[i]);
}
  • 全程更新
简介:操作一次,更新一次(就是这么简单)
形式:
在上述for循环中,每执行完
【变量=条件函数(变量与nums[i],nums[i])】
就可以紧跟着更新操作。
如:ans=Math.max(变量,ans);

  拿好菜刀,来看看下面的“菜”吧!
53.最大子数组和
image.png
【前排】别看我,我是不会告诉你答案的! 先好好想想如何使用上面的两把菜刀!

-----------------------------
【提示】以nums[i]元素作为结束元素,如果当前元素nums[i]加上上一个元素值会更大则进行连接;

152. 乘积最大子数组
image.png

【前排】别看我,我是不会告诉你答案的! 将+改为了*,如果遇到了负数会有什么情况?

-----------------------------
【提示】以nums[i]元素作为结束元素,如果能够跟前面的值组合成更大的值,则进行连接,否则单独开始新的匹配。此题中由于是乘法,故最大值有两种情况:(1)正数*最大值;(2)负数*最小值

ANS:
【53】(没做出来也别灰心~~)

public int maxSubArray(int[] nums) {
     int ans=nums[0];
     int len=nums.length;
     if(len==1){
         return ans;
     }
     // 贪心:以nums[i]元素作为结束元素,如果加上上一个元素值会更大则进行更新;
     for(int i=1;i<len;i++){
         nums[i]=Math.max(nums[i],nums[i]+nums[i-1]);
         ans=Math.max(nums[i],ans);
     }
     return ans;
    }

【152】

public int maxProduct(int[] nums) {
        int len=nums.length;
        int maxn=nums[0];
        int preMax=nums[0];
        int preMin=nums[0];
        // 贪心:以nums[i]元素作为结束元素,如果能够跟前面的值组合成更大的值,则进行连接,否则单独开始新的匹配。此题中由于是乘法,故最大值有两种情况:(1)正数*最大值;(2)负数*最小值
        for(int i=1;i<len;i++){
            // 如果当前值是负数,则交换preMax和preMin,以满足前面两种情况
            if(nums[i]<0){
                int temp=preMax;
                preMax=preMin;
                preMin=temp;
            }
           preMax=Math.max(preMax*nums[i],nums[i]);
           preMin=Math.min(preMin*nums[i],nums[i]);
           // 更新结果
           maxn=Math.max(maxn,preMax);
        }
        return maxn;
    }

【小试牛刀】(不要死记,灵活应对)
  在152中,有最大值和最小值两种交替情况,下面这题也是有类似的情况,可以刺激一下思维!
978. 最长湍流子数组
image.png

【提示】以nums[i]作为结尾元素(判断是升还是降),如果是升那就寻找前面的降;如果是降就寻找前面的升;如果相等,那就重置。
【ans】

public int maxTurbulenceSize(int[] arr) {
      int up=1,down=1,ans=1,len=arr.length;
      for(int i=1;i<len;i++){
           if(arr[i]>arr[i-1]){
               up=down+1;
               // 当前是升,如果要是降的话,就只能以arr[i]作为降的起始点
               down=1;
           } else if(arr[i]<arr[i-1]){
               down=up+1;
               up=1;
           } else {
               up=1;
               down=1;
           }
           ans=Math.max(ans,Math.max(up,down));
      }
      return ans;
    }
指定条件收索子数组

  在数组中搜索一定条件下关于子数组的一些属性,如子数组的个数。此时,大部分得采用哈希表以降低时间复杂度,如HashMap,HashSet,普通数组等。

  看题
560. 和为 K 的子数组
image.png
image.png

【简述】一次遍历:维护一个累加和,通过哈希表对目标值进行查询,记录,再添加到哈希表中。
【ans】

 public int subarraySum(int[] nums, int k) {
       int len=nums.length;
       HashMap<Integer,Integer> record=new HashMap();
       record.put(0,1);
       int ans=0;
       int sum=0;
       // 通过hashMap记录过去的累计和,替换二重遍历。
       for(int i=0;i<len;i++){
            sum+=nums[i];
            if(record.containsKey(sum-k)){
                ans+=record.get(sum-k);
            }
            record.put(sum,record.getOrDefault(sum,0)+1);
       }
       return ans;
    }

974. 和可被 K 整除的子数组
image.png
【简述】与上述基本一样,只是查询目标值的方法不一样,采用余数方式进行收索。

可被整除一般会用到同余法。
如:两个整数相减,什么时候会得到一个整数?
   那肯定是对某一个数取余,且余数相等的情况下。
但是要注意负数的情况,可套用的公式:k=(num%mod+mod)%mod;
可以尝试-34相减是否可以被7整除。

【ans】

 public int subarraysDivByK(int[] nums, int k) {
       int len=nums.length;
       HashMap<Integer,Integer> record=new HashMap();
       record.put(0,1);
       int ans=0;
       int sum=0;
       int mod=0;
       for(int i=0;i<len;i++){
            sum+=nums[i];
            // 负数变正
            mod=(sum%k+k)%k;
            int pre=record.getOrDefault(mod,0);
            ans+=pre;
            record.put(mod,pre+1);
       }
       return ans;
    }

1157. 子数组中占绝大多数的元素
image.png

【简述】不要被困难吓到,此处可以采用哈希表暴力通过,嘻嘻嘻。通过一个数组记录该区间内元素的出现个数。
【ans】

  private int []nums;
    private int []ans;
    private int max;
    public MajorityChecker(int[] arr) {
        nums=arr;
         max=arr[0];
        for(int n:arr){
            max=Math.max(n,max);
        }
    }
    
    public int query(int left, int right, int threshold) {
        ans=new int [max+1];
        for(int i=left;i<=right;i++){
            if(++ans[nums[i]]>=threshold){
                return nums[i];
            }
        }
        return -1;
    }

本文到此结束!希望对你有所帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值