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 ;

    }
}

leetcode之前缀和刷题总结3_第1张图片
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 ;
}
}

leetcode之前缀和刷题总结3_第2张图片
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 ;
    }
}

leetcode之前缀和刷题总结3_第3张图片

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 ;
    }
}

leetcode之前缀和刷题总结3_第4张图片
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 ;
        

    }
}

leetcode之前缀和刷题总结3_第5张图片
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);
 */

leetcode之前缀和刷题总结3_第6张图片
思路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);
 */

leetcode之前缀和刷题总结3_第7张图片
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 ;
    }
}

leetcode之前缀和刷题总结3_第8张图片

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 ;
    }
}

leetcode之前缀和刷题总结3_第9张图片
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 ;
    }
}

leetcode之前缀和刷题总结3_第10张图片
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 ;
    }
}

leetcode之前缀和刷题总结3_第11张图片
思路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 ;
    }
}

leetcode之前缀和刷题总结3_第12张图片

你可能感兴趣的:(算法与数据结构,leetcode,算法,矩阵,前缀和,差分数组)