leetcode之前缀和刷题总结3

leetcode之前缀和刷题总结3

1-找到最高海拔
题目链接:题目链接戳这里!!!

思路:差分数组+高度差,求出海拔高度,同时找出最高海拔就可以。

先水个easy题,自我感动一下。

class Solution {
    public int largestAltitude(int[] gain) {
        int [] high = new int [gain.length+1] ;
        high[0] = 0 ;
        int ans = 0 ;
        for(int i=0; i<gain.length; i++){
            high[i+1] = gain[i] + high[i] ;
            ans = Math.max(ans, high[i+1]) ;
        }
        return ans ;

    }
}

在这里插入图片描述
2-每个元音包含偶数次的最长子字符串
题目链接:题目链接戳这里!!!

思路:将 5 个元音字母出现次数的奇偶视为一种状态,一共有 32 种状态,不妨使用一个整数代表状态,第 0 位为 1 表示 a 出现奇数次,第一位为 1 表示 e 出现奇数次……以此类推。仅有状态 0符合题意。

而如果子串 [0,i] 与字串 [0,j] 状态相同,那么字串 [i+1,j] 的状态一定是 0,因此可以记录每个状态第一次出现的位置,此后再出现该状态时相减即可。
需要注意状态 0 首次出现的位置应该设定为 -1。

在计算状态的时候可以利用异或运算。

class Solution {
    public int findTheLongestSubstring(String s) {
        int n = s.length() ;
        int [] states = new int [32] ;
        Arrays.fill(states,Integer.MAX_VALUE) ;
        states[0] = -1 ;
        int cur = 0, ans = 0 ;
        for(int i=0; i<s.length(); i++){
            char ch = s.charAt(i) ;
            switch(ch){
                case 'a': cur^=1; break ;
                case 'e': cur^=2; break ;
                case 'i': cur^=4; break ;
                case 'o': cur^=8; break ;
                case 'u': cur^=16; break ;
                default:break ;
            }
        if(states[cur]==Integer.MAX_VALUE){
            states[cur] =i ;
        }else{
            ans = Math.max(ans, i-states[cur]) ;
        }
    }
    return ans ;
}
}

在这里插入图片描述
3-可获得的最大点数
题目链接:题目链接戳这里!!!

思路:滑动窗口
先对前k个数累加求和,然后依次从后最后一个先前加,从第k-1个向前减,维护窗口中的值最大即可。

class Solution {
    public int maxScore(int[] cardPoints, int k) {
        int res = 0, sum = 0 ;
        for(int i=0; i<k; i++){
            sum += cardPoints[i] ;
        }
        res = sum ;
        for(int i=0; i<k; i++){
            sum += cardPoints[cardPoints.length-1-i] ;
            sum -= cardPoints[k-i-1] ;
            res = Math.max(res, sum) ;
        }
        return res ;
    }
}

在这里插入图片描述

4-形成两个异或相等数组的三元组数目
题目链接:题目链接戳这里!!!

思路:最终的a==b等价求a^b == 0 ,如果a与b异或等于0,则对应的三元组所拥有的满足要求的个数为对应数组下标的差值。

class Solution {
    public int countTriplets(int[] arr) {
        int res = 0 ;
        for(int i=0; i<arr.length; i++){
            int t = arr[i] ;
            for(int j=i+1; j<arr.length; j++){
                t ^= arr[j] ;
                if(t==0){
                    res += j - i ;
                }
            }
        }
        return res ;
    }
}

在这里插入图片描述
5-左右两边的子数组和相等
题目链接:题目链接戳这里!!!

思路:求出前缀和,然后从前先后遍历前缀和数组,判断是否存在左右两边的子数组和相等的情况。

class Solution {
    public int pivotIndex(int[] nums) {
        int [] sums = new int[nums.length+1] ;

        for(int i=1; i<sums.length; i++){
            sums[i] = sums[i-1] + nums[i-1] ;
        }

        for(int i=1; i<sums.length; i++){
            if(sums[i-1]==sums[sums.length-1]-sums[i]){
                return i-1 ;
            }
        }
        return -1 ;
        

    }
}

在这里插入图片描述
6-二维子矩阵的和
题目链接:题目链接戳这里!!!

思路1:二维按行变成多个一维的,对每个一维的求前缀和,每个一维的累加即可。

class NumMatrix {
    int [][] matrix ;
    public NumMatrix(int[][] matrix) {
        for(int i=0; i<matrix.length; i++){
            for(int j=1; j<matrix[0].length; j++){
                matrix[i][j] += matrix[i][j-1] ; 
            }
        }
        this.matrix = matrix ;
    }
    
    public int sumRegion(int row1, int col1, int row2, int col2) {
        int res = 0 ;
        for(int i=row1; i<=row2; i++){
            res += (col1-1>=0 ?  matrix[i][col2] - matrix[i][col1-1] : matrix[i][col2]) ;
        }
        return res ;
        
    }
}

/**
 * Your NumMatrix object will be instantiated and called as such:
 * NumMatrix obj = new NumMatrix(matrix);
 * int param_1 = obj.sumRegion(row1,col1,row2,col2);
 */

在这里插入图片描述
思路2:直接用公式求解二维前缀和。

class NumMatrix {
    int [][] f ;
    public NumMatrix(int[][] matrix) {
         f = new int [matrix.length+1][matrix[0].length+1] ;
        for(int i=0; i<matrix.length; i++){
            for(int j=0; j<matrix[0].length; j++){
                f[i+1][j+1] = f[i+1][j] + f[i][j+1] + matrix[i][j] - f[i][j] ;
            }
        }  
    }
     public int sumRegion(int row1, int col1, int row2, int col2) {
         return f[row2+1][col2+1] - f[row1][col2+1] - f[row2+1][col1] + f[row1][col1] ;
     }
}

/**
 * Your NumMatrix object will be instantiated and called as such:
 * NumMatrix obj = new NumMatrix(matrix);
 * int param_1 = obj.sumRegion(row1,col1,row2,col2);
 */

在这里插入图片描述
7-元素和为目标值的子矩阵数量
题目链接:题目链接戳这里!!!

思路:我们枚举子矩阵的上下边界,并计算出该边界内每列的元素和,则原问题转换成了如下一维问题,然后使用前缀和+hash表的方式解决问题。

class Solution {
    public int numSubmatrixSumTarget(int[][] matrix, int target) {
        int ans = 0 ;
        int m = matrix.length ;
        int n = matrix[0].length ;
        for(int i=0; i<m; i++){
            int [] sum = new int [n] ;
            for(int j=i; j<m; j++){
                for(int c=0; c<n; c++){
                     sum[c] += matrix[j][c] ;
                }
                ans += f(sum, target) ;
            }
        }
        return ans ;
    }
    public int f(int [] sum, int target){
        int pre=0, ans = 0 ;
        Map<Integer, Integer> map = new HashMap<>() ;
        map.put(0,1) ;
        for(int x : sum){
            pre += x ;
            if(map.containsKey(pre-target)){
                ans += map.get(pre-target) ;
            }
            map.put(pre,map.getOrDefault(pre,0)+1) ;
        }
        return ans ;
    }
}

在这里插入图片描述

8-和为奇数的子数组数目
题目链接:题目链接戳这里!!!

思路:前缀和+数学
依次求出数组的前缀和,使用odd表示奇数的前缀和,even表示偶数的前缀和,根据前缀和判断当前的数字是奇数还是偶数。

class Solution {
    public int numOfSubarrays(int[] arr) {
        //odd表示奇数前缀和,even表示偶数前缀和
        int sum = 0, odd=0, even=1,ans=0, mod=1000000007;
        for(int i=0; i<arr.length; i++){
            sum += arr[i] ;
            ans = (ans+(sum%2==0 ? odd : even)) % mod ;
            if(sum%2==0){
                even++ ;
            }else{
                odd ++ ;
            }
        }
        return ans ;
    }
}

在这里插入图片描述
9-检查是否区域内所有整数都被覆盖
题目链接:题目链接戳这里!!!

思路:模拟过程,枚举left到right之间的值,对于任意一个值判断是否在区间内,若有任意值不在区间内,则返回false,否则返回true。

class Solution {
    public boolean isCovered(int[][] ranges, int left, int right) {
        for(int i=left; i<=right; i++){
            boolean flag = false ;
            for(int [] arr : ranges){
                int l = arr[0], r = arr[1] ;
                if(i>=l && i<=r){
                    flag = true ;
                    break ;
                }
            }
            if(!flag){
                return false ;
            }
        }
        return true ;
    }
}

在这里插入图片描述
10-和为k的子数组
题目链接:题目链接戳这里!!!

思路1:求出前缀和,然后通过前缀和找出所有和为k的子数组,该方法的时间复杂度为O(n^2),虽然AC了,但是算法效率并不高。

class Solution {
    public int subarraySum(int[] nums, int k) {
        int n = nums.length ;
        int [] sums = new int [n+1] ;
        for(int i=1; i<=n; i++){
            sums[i] = sums[i-1] + nums[i-1] ;
        }
        int ans = 0 ;
        for(int i=0; i<=n; i++){
            for(int j=i+1; j<=n; j++){
                if(i==0){
                    if(sums[j]==k){
                        ans ++ ;
                    }
                }else{
                    if(sums[j]-sums[i]==k){
                        ans ++ ;
                    }
                }
            }
        }
        return ans ;
    }
}

在这里插入图片描述
思路2:前缀和+hash表,时间复杂度为O(n),效率相对较高。

class Solution {
    public int subarraySum(int[] nums, int k) {
       Map<Integer,Integer> map = new HashMap<>() ;
       int ans=0, sum=0;
       map.put(0,1) ; //初始化前缀和为0的个数为1
       for(int i=0; i<nums.length; i++){
           sum += nums[i] ;
           ans += map.getOrDefault(sum-k,0) ;
           map.put(sum,map.getOrDefault(sum,0)+1) ;
       }
       return ans ;
    }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值