• 力扣P525. 连续数组、P523. 连续的子数组和


    P525

    原题链接 https://leetcode-cn.com/problems/contiguous-array/

    解题思路

    最近学的 前缀和

    构造一个新数组 store 长度为原数组的 length+1
    store[i+1] 存储的值是 原来数组中 0~ i 位置上的元素的和,举个例子:

    • 原数组nums为 [1,2,3,4,5]
    • 那么store数组 的值为 [0,1,1+2,1+2+3,1+2+3+4,1+2+3+4]

    那么当我们要求原数组nums i到j所有元素的和,就可以 使用 store[j+1] - store[i]
    举例说明:nums索引为 1~3的和为 2+3+4= store[4] - store[1]

    有了前缀和之后,就可以子序列 i~j的元素求和 从O(n) 降到 O(1)

    代码

    class Solution {
        public int findMaxLength(int[] nums) {
    
            int[] store = new int[nums.length + 1];
            for (int i = 0; i < nums.length; i++) {
                store[i + 1] = nums[i] + store[i];
            }
    
            //从i~j之间的求和为 store[j]-store[i]
    
    
            //1、首先这个连续子数组为  偶数长 【0和1各一半,所以是偶数】
            //2、从最长的开始检查
            //如  0、1、1、1、1、0、0、0、0、0
            // 先假设  最长先为10, 索引为 0~9 的和看是否为  5
    
           //如果nums长度为偶数,则最大的长度为  length ,最大索引为 nums.length - 1
           //如果nums长度为奇数,则最大的长度为  length-1 ,最大索引为 nums.length - 2
           int first = (nums.length & 1) == 0 ? nums.length - 1 : nums.length - 2;
    
            for(int j=first;j>0;j=j-2){
                for(int i=0;i<nums.length-j; i++ ){
                    //i ~ i+j 的元素的和 必须满足是 跨度的 一半
                    if((store[i+j+1] - store[i])*2== j+1  )   
                        return j+1;
                }
            }
            return 0;
    
        }
    }
    

    P523

    原题链接 https://leetcode-cn.com/problems/continuous-subarray-sum/

    解题思路

    这题挺折腾我也是看了很多题解写的,说实在的这道题的难度 应该是困难级才对,能直接自己想出O(n)的复杂度的该给困难级,这题复杂度O(n2)都会超时。你也可以看一下通过率。即便是我已经看明白了思路,自己coding也错误提交了三次

    前缀和

    关于前缀和 你首先应该 懂。 看 暴力+前缀和

    同余定理

      x%k==a 且 y%k==a  //a为任意余数,包括0  
    则  有 x-y 的绝对值为k的倍数
    

    把x,y分别当做前缀和中的两个元素,则 如果要求(store[i]- store[j])%k==0store[i]%k== store[j]%k
    那么就要求 前缀和数组store中是否能 找到两个数i,j 满足 store[i]%k== store[j]%k

    HashMap

    要找到两个数满足 store[i]%k== store[j]%k 的i,j 就转换成了类似 找相同两个数方法,正常为O(n2)的复杂度,但使用hashmap就能转换成O(n)的复杂度

    官方题解比较晦涩的就是关于 map.put(0, -1);这句代码的。 原文写的是 规定空的前缀的结束下标为 -1,由于空的前缀的元素和为 0,因此在哈希表中存入键值对 (0,-1) 反正我开始理解了半天,懂不起。

    后来自己想明白了。如果说前缀和数组store本身有一个元素i的值是 k的倍数,也就是说如果store[i]%k==0 代表 0i-1 索引元素的和 已经就是k的倍数了。

    为了让代码更好理解我就改成了这样的

    这样的效果就等同于map.put(0, -1)

      int y= store[i]%k;  //y为当前前缀和的余数
    
      //只要y==0 就代表 `0`到 `i-1` 索引元素的和 已经就是k的倍数了
      //注意 store[1]存储nums[0],此时 store只有一个元素,满足题目要求  子数组大小 至少为 2
      //所以 且 i>=2
      if(y==0&&i>=2)      
        return  true;
    

    代码

    class Solution {
      public boolean checkSubarraySum(int[] nums, int k) {
           if(nums==null|| nums.length<2)
                return false;
                
            //首先构造一个   前缀和 数组
            int [] store = new int[nums.length+1] ;
    
            for(int i=0;i<nums.length;i++){
                store[i+1]= store[i]+ nums[i];
            }
            //store[1]= nums[0]
            //store[2]=nums[0]+ nums[1]
            Map<Integer,Integer> map= new HashMap<>();
    
            for(int i=1;i<nums.length+1 ;i++){
               int y= store[i]%k;      //当前前缀和%k
               if(y==0&&i>=2)
                    return  true;
                if( map.get(y)==null){  //如果没有相同余数的索引,则将当前余数的索引放入map
                    map.put(y,i);
                }else if(i-map.get(y) >=2){ //找到了余数也为y的索引  为  map.get(y)
                                            //因为 子数组大小 至少为 2,索引索引差值为2
                    return true;
                }
            }
            return false;
        }
    }
    
  • 相关阅读:
    iscroll.js
    HTML 第九章总结
    HTML第八章总结
    HTML第七章总结
    HTML第六章总结
    HTML第五章总结
    HTML第四章总结
    HTML第三章总结
    HTML第二章总结
    HTML第一章总结
  • 原文地址:https://www.cnblogs.com/mxjhaima/p/14853725.html
Copyright © 2020-2023  润新知