算法日常训练11.15

本文探讨了如何使用前缀和与贪心算法解决数组相关问题,包括最大单元装载问题和二维数组求和。通过示例代码展示了如何实现一维和二维数组的前缀和计算,并在最大子矩阵和问题中应用这些技巧。虽然对于某些复杂问题,纯前缀和方法可能不够,但它们仍然是高效解决问题的重要工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 曾经在力扣评论区看见这样一句话,“sort函数就是简单题的爹”,这里就直接用sort函数,使用lambda表达式写比较器,按箱子能装的最大数量排序,先选最大的箱子,贪心的思想

class Solution {
    public int maximumUnits(int[][] boxTypes, int truckSize) {
        Arrays.sort(boxTypes,(o1,o2)->o2[1]-o1[1]);
        int res=0;//结果
        int index=0;//指向最大的箱子
        while(truckSize>0&&index<boxTypes.length){
            if(truckSize>=boxTypes[index][0]){
                truckSize-=boxTypes[index][0];
                res+=boxTypes[index][1]*boxTypes[index][0];
                index++;
            }
            else{
                res+=boxTypes[index][1]*truckSize;
                truckSize=0;
            }
        }
        return res;
    }
}

前缀和:

昨天写到了二维数组前缀和的问题,现在系统复习一下,首先是一维数组,前缀和的作用就是为了方便求区域和

如数组  1,2,3,4,5,6

对应前缀和  1,3,6,10,15,21

不难发现前缀和的计算就是前一个前缀和加上当前数字,前缀和主要用来解决区间和问题,比如这里2,4区间的和,就可以用15-3即sum【4】-sum【2-1】的值,i,j就是sum【j】-sum【i-1】利用小学知识就很容易理解,但是要注意这里比如0-2区间的和,就不能sum【2】-sum【0-1】,其实就是sum【2】的值,还有一种前缀和的写法是前缀和保存前面几个数的和,这里就是 0,1,3,6,10,15,21,这样i,j就是sum【j+1】-sum【i】,就不要判断0的情况,力扣中对应前缀和的题:

直接附上代码:

class NumArray {
    int[] sum;//保存前缀和
    public NumArray(int[] nums) {
        this.sum=new int[nums.length];
        sum[0]=nums[0];
        for(int i=1;i<nums.length;i++){
            sum[i]=sum[i-1]+nums[i];
        }
    }
    
    public int sumRange(int left, int right) {
        if(left==0) return sum[right];
        return  sum[right]-sum[left-1];
    }
}

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray obj = new NumArray(nums);
 * int param_1 = obj.sumRange(left,right);
 */

 二维前缀和:

一维前缀和用的是小学计算知识,那么二维就是用的小学几何知识

首先初始化,sum[0][0]一定是等于arr[0][0]的,

然后第一行和第一列,可以看做一维数组的前缀和分析

不是第一行和第一列的,利用几何分析,当前位置就是一个大矩形,上面的矩形加下面的,加上当前值,再减当前值,就是该大矩形面积

在任意一个位置矩形时,除了等于0时的特殊位置,都可以用大矩形去减,再加上重复区域,语言表达有点困难,需要使用时还是需要画图理解。

 

class NumMatrix {
    int[][] sum;
    public NumMatrix(int[][] matrix) {
        int m=matrix.length;
        int n=matrix[0].length;
        sum=new int[m][n];
        sum[0][0]=matrix[0][0];
        for(int i=1;i<m;i++){
            sum[i][0]=sum[i-1][0]+matrix[i][0];//第一列
        }
        for(int j=1;j<n;j++){
            sum[0][j]=sum[0][j-1]+matrix[0][j];//第一行
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                sum[i][j]=sum[i-1][j]+sum[i][j-1]+matrix[i][j]-sum[i-1][j-1];
            }
        }
    }
    
    public int sumRegion(int row1, int col1, int row2, int col2) {
        if(row1==0&&col1==0) return sum[row2][col2];
        if(row1==0) return sum[row2][col2]-sum[row2][col1-1];
        if(col1==0) return sum[row2][col2]-sum[row1-1][col2];
        return sum[row2][col2]-sum[row2][col1-1]-sum[row1-1][col2]+sum[row1-1][col1-1];
    }
}

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

 来个二维数组前缀和的应用,基本就是把上题的代码粘贴过去,但是这里列举了所以矩形的左上角和右下角,用了四层循环,ac是ac了,但是就差那么一点就垮了,毕竟是困难题,纯用前缀和应该是不可能的,这里暴力ac了属于侥幸了

class Solution {
    int[][] sum;
    public int maxSumSubmatrix(int[][] matrix, int k) {
        int m=matrix.length;
        int n=matrix[0].length;
        sum=new int[m][n];
        sum[0][0]=matrix[0][0];
        for(int i=1;i<m;i++){
            sum[i][0]=sum[i-1][0]+matrix[i][0];//第一列
        }
        for(int j=1;j<n;j++){
            sum[0][j]=sum[0][j-1]+matrix[0][j];//第一行
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                sum[i][j]=sum[i-1][j]+sum[i][j-1]+matrix[i][j]-sum[i-1][j-1];
            }
        }
        int max=Integer.MIN_VALUE;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                for(int a=m-1;a>=i;a--){
                    for(int b=n-1;b>=j;b--){
                        int num=sumRegion(i,j,a,b);
                        
                        if(num<=k){
                            max=Math.max(num,max);
                        }
                    }
                }
            }
        }
        return max;
    }
    public int sumRegion(int row1, int col1, int row2, int col2) {
        if(row1==0&&col1==0) return sum[row2][col2];
        if(row1==0) return sum[row2][col2]-sum[row2][col1-1];
        if(col1==0) return sum[row2][col2]-sum[row1-1][col2];
        return sum[row2][col2]-sum[row2][col1-1]-sum[row1-1][col2]+sum[row1-1][col1-1];
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值