leecode 解题总结:363. Max Sum of Rectangle No Larger Than K

本文介绍了一种求解二维矩阵中最大子矩阵和的方法,通过将问题转换为求解一维子数组的最大连续和来简化计算过程。利用累加和与集合数据结构实现了高效的求解算法,并给出了具体的实现代码。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <set>
using namespace std;
/*
问题:
输入: 
2 3(行和列) 
1 -2 3 
-4 5 6 

3 5
9 -8 1 3 -2
-3 7 6 -2 4
6 -4 -4 8 -7
输出: 
12
-2 3
5 6

19
9 -8 1 3
-3 7 6 -2
6 -4 -4 8
*/

//求一维子数组最大连续和
int maxSubArray(vector<int>& nums)
{
	if(nums.empty())
	{
		return 0;
	}
	int size = nums.size();
	int sum = 0;
	int maxSum = 0;
	for(int i = 0 ; i  < size ; i++)
	{
		sum = max(nums.at(i) , sum + nums.at(i));
		maxSum = max(maxSum , sum);
	}
	return maxSum;
}

//求一维子数组中最大连续和<k的最大值,先不断求累加和数组,然后
//设需要找到的数为val , 即val < k 且val是最接近的,等同于求这样的累加和的位置
//寻找之前的累加和val > 当前元素的累加和curSum  - k 的位置,然后找到val对应位置为p,用curSum - val,即可得到位置p到当前位置累加和<k的最大值
//即val (min) > curSum - k, curSum - val(min) < k
int maxSubArray_LessK(vector<int>& nums , int k)
{
	if(nums.empty())
	{
		return 0;
	}
	int curSum = 0 ;
	int best = 0;
	int size = nums.size();
	set<int> sums;
	for(int i = 0 ; i < size ; i++)
	{
		curSum += nums.at(i);
		auto it = sums.upper_bound(curSum - k);//找到前面某元素的累加和略大于curSum-k中的最小值val,从而保证该元素与直到当前元素的累加和(curSum - val)略小于k
		if(it != sums.end() )
		{
			best = max(best , curSum - *it);
		}
		sums.insert(curSum);
	}
	return best;
}

int maxSubArray_NoMoreThanK(vector<int>& nums , int k)
{
	if(nums.empty())
	{
		return 0;
	}
	int curSum = 0 ;
	int best = INT_MIN;
	int size = nums.size();
	set<int> sums;
	sums.insert(0);//确保如果当前元素的累加和 < k,那么当前元素的累加和是一个解
	for(int i = 0 ; i < size ; i++)
	{
		curSum += nums.at(i);
		auto it = sums.lower_bound(curSum - k);//找到前面某元素的累加和略大于curSum-k中的最小值val,从而保证该元素与直到当前元素的累加和(curSum - val)略小于k
		if(it != sums.end() )
		{
			best = max(best , curSum - *it);
		}
		sums.insert(curSum);
	}
	return best;
}

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) 
    {
    	if(matrix.empty())
    	{
    		return 0;
    	}
    	int row = matrix.size();
    	int col = matrix.at(0).size();
    	int maxSum = INT_MIN;
    	for(int i = 0 ; i < col ; i++)
    	{
    		vector<int> nums(row , 0);
    		for(int j = i ; j < col ; j++)
    		{
    			set<int> sums;
    			sums.insert(0);//用于插入累加和元素
    			int curSum = 0;
    			int curMax = INT_MIN;
    			//计算从第i列到第j列中,每一行的元素和,将所有每一行的元素和作为一维子数组,然后求该子数组最大连续和
    			for(int x = 0; x < row ; x++)
    			{
    				//累加了上一列中同一行的元素
    				nums.at(x) += matrix.at(x).at(j);
    				curSum += nums.at(x);//计算累加和
    				auto it = sums.lower_bound(curSum - k);//寻找VALmin >= curSum - k ,那么curSum - VALmin <= k,计算出从寻找位置到当前位置最接近k的累加和
    				if(it != sums.end())
    				{
    					curMax = max(curMax , curSum - *it);
    				}
    				sums.insert(curSum);
    			}
    			maxSum = max(maxSum , curMax);
    		}
    	}
    	return maxSum;
    }
};

//求二维连续子矩阵的最大和,采用遍历当前行,尝试将当前行及其以下部分的行中,每一列元素累加,转化为求一维中最大连续子数组之和
int maxSubMatrix(vector<vector<int> >& matrix)
{
	if(matrix.empty())
	{
		return 0;
	}
	int row = matrix.size();
	int col = matrix.at(0).size();
	int maxSum = INT_MIN;
	for(int i = 0 ; i < row ; i++)
	{
		vector<int> nums(col , 0);
		for(int j = i ; j < row ; j++)
		{
			//计算从第i行到第j行中,每一列的元素和,将所有每一列的元素和作为一维子数组,然后求该子数组最大连续和
			for(int k = 0; k < col ; k++)
			{
				//累加了上一行中同一列的元素
				nums.at(k) += matrix.at(j).at(k);
			}
			//求连续几行之间的最大连续和
			int sum = maxSubArray(nums);
			maxSum = max(maxSum , sum);
		}
	}
	return maxSum;
}

//以列主要计算方面,将两列之间同一行的元素累加,转化为一维数组求最大连续和,行n,列m,时间复杂度为O(m^2 * n)
int maxSubMatrix_BaseColumn(vector<vector<int> >& matrix)
{
	if(matrix.empty())
	{
		return 0;
	}
	int row = matrix.size();
	int col = matrix.at(0).size();
	int maxSum = INT_MIN;
	for(int i = 0 ; i < col ; i++)
	{
		vector<int> nums(row , 0);
		for(int j = i ; j < col ; j++)
		{
			//计算从第i列到第j列中,每一行的元素和,将所有每一行的元素和作为一维子数组,然后求该子数组最大连续和
			for(int k = 0; k < row ; k++)
			{
				//累加了上一列中同一行的元素
				nums.at(k) += matrix.at(k).at(j);
			}
			//求连续几行之间的最大连续和
			int sum = maxSubArray(nums);
			maxSum = max(maxSum , sum);
		}
	}
	return maxSum;
}



void process()
{
	 vector<vector<int> > matrix;
	 int value;
	 int row;
	 int col;
	 int result;
	 while(cin >> row >> col )
	 {
		 matrix.clear();
		 for(int i = 0 ; i < row ; i++)
		 {
			 vector<int> nums;
			 for(int j = 0 ; j < col ; j++)
			 {
				cin >> value;
				nums.push_back(value);
			 }
			 matrix.push_back(nums);
		 }
		 result = maxSubMatrix_BaseColumn(matrix);
		 cout << result << endl;;
	 }
}

void test()
{
	set<int> setNum;
	setNum.insert(1);
	int k = 10;
	int curNum = 1;
	auto it = setNum.lower_bound(curNum - k);
	int best = 0;
	if(it != setNum.end())
	{
		best = max(best , curNum - *it);
	}
	setNum.insert(curNum);
}

int main(int argc , char* argv[])
{
	process();
	//test();
	getchar();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值