zoukankan      html  css  js  c++  java
  • 力扣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;
        }
    }
    
  • 相关阅读:
    HDU 5528 Count a * b 欧拉函数
    HDU 5534 Partial Tree 完全背包
    HDU 5536 Chip Factory Trie
    HDU 5510 Bazinga KMP
    HDU 4821 String 字符串哈希
    HDU 4814 Golden Radio Base 模拟
    LA 6538 Dinner Coming Soon DP
    HDU 4781 Assignment For Princess 构造
    LA 7056 Colorful Toy Polya定理
    LA 6540 Fibonacci Tree
  • 原文地址:https://www.cnblogs.com/mxjhaima/p/14853725.html
Copyright © 2011-2022 走看看