目录
一、集合的子集合
1.1 回溯法思路
1.2 回溯法代码及解析
1.3 其他人思路及代码供参考
1.4 分治法(动态规划)
1.5 位运算法实现穷举
二、连续子数组的最大和
2.1 类似股票最大值
2.2 推算方法
2.3 动态规划方法
三、最大子矩阵和
3.1 题干
3.2 错误的积分图的方法
3.3 在连续子数组基础上更改
四、直方图中面积最大的矩形
4.1 题干
4.2 思路
4.3 解答
五、最大全1子矩阵
5.1 投影法
5.2 分解为面积最大的直方图子问题
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
oj:https://leetcode-cn.com/problems/subsets/
回溯法及思路
本题的回溯法算法设计如图所示:
下面代码及思路解析:
#include
#include
#include
#include
using namespace std;
class Solution {
public:
vector> subsets(vector& nums) {
vector>sub_sets;
int length = nums.size();
if (length < 1){
vector empty;
sub_sets.push_back(empty);
return sub_sets;
}
vectorcurrent_set;
set>all_sub_sets;
find_all_subsets(nums, 0, current_set, all_sub_sets);
for (auto item : all_sub_sets){
sub_sets.push_back(item);
}
return sub_sets;
}
void find_all_subsets(vector& nums, int loc, vector ¤t_set, set> & all_sub_sets){
all_sub_sets.insert(current_set);
int length = nums.size();
if (loc >= length){
return;
}
find_all_subsets(nums, loc + 1, current_set, all_sub_sets);
current_set.push_back(nums[loc]);
find_all_subsets(nums, loc + 1, current_set, all_sub_sets);
current_set.pop_back();
return;
}
};
int main(){
vectorset = {1,2,3};
Solution s1;
vector>subsets_it = s1.subsets(set);
for (auto sub_set : subsets_it){
if (sub_set.empty())cout << endl;
else{
for (auto item : sub_set){
cout << item << " ";
}
cout << endl;
}
}
int end; cin >> end;
return 0;
}
相对更精简的代码:
3
2
2 3
1
1 3
1 2
1 2 3
class Solution {
public:
vector> subsets(vector& nums) {
vector>sub_sets;
int length = nums.size();
if (length < 1){
vector empty;
sub_sets.push_back(empty);
return sub_sets;
}
vectorcurrent_set;
find_all_subsets(nums, 0, current_set, sub_sets);
return sub_sets;
}
void find_all_subsets(vector& nums, int loc, vector ¤t_set, vector> & all_sub_sets){
int length = nums.size();
if (loc == length){
all_sub_sets.push_back(current_set);
return;
}
find_all_subsets(nums, loc + 1, current_set, all_sub_sets);
current_set.push_back(nums[loc]);
find_all_subsets(nums, loc + 1, current_set, all_sub_sets);
current_set.pop_back();
return;
}
};
作者:yi-shi-yi-mu-zi
链接:https://leetcode-cn.com/problems/subsets/solution/fen-zhi-fa-ji-qi-die-dai-xun-huan-shi-xian-he-di-g/
来源:力扣(LeetCode)
https://leetcode-cn.com/problems/subsets/solution/fen-zhi-fa-ji-qi-die-dai-xun-huan-shi-xian-he-di-g/
void compute(vector>&subset_set,
vector& nums,vector&now_set,int i){
if(i>=nums.size()){
return;
}
now_set.push_back(nums[i]);
subset_set.push_back(now_set);
compute(subset_set,nums,now_set,i+1);
now_set.pop_back();
compute(subset_set,nums,now_set,i+1);
return;
}
class Solution {
public:
vector> subsets(vector& nums) {
vector>subset_set;//保存最终结果
vectornow_set={};
subset_set.push_back(now_set);
compute(subset_set,nums,now_set,0);
return subset_set;
}
};
分治思想,具体如下图:
也可以从动态规划的角度来理解此代码
根据如上思路写出下面代码:
class Solution {
public:
vector> subsets(vector& nums) {
vector>result = { {} };
//result.push_back({});
int length = nums.size();
if (length < 1)return result;
for (int idx = 0; idx < length; idx++){
int current = nums[idx];
int copy_len = result.size();
for (int idx_copy = 0; idx_copy < copy_len; idx_copy++){
vector copy = result[idx_copy];
copy.push_back(current);
result.push_back(copy);
}
}
return result;
}
};
注意事项:
用二进制中数位来实现当前元素选中与否
代码实现:
class Solution {
public:
vector> subsets(vector& nums) {
vector>result ;
int length = nums.size();
long long int mask = 0x0000000000000001;
long long int top =( mask << length);
for (long long int select = 0; select < top; select++){
vector sub;
for (long long int num_item = 0; num_item < length; num_item++){
if ((mask << num_item)&select){
sub.push_back(nums[num_item]);
}
}
result.push_back(sub);
}
return result;
}
};
剑指offer P237
OJ:https://www.nowcoder.com/practice/459bd355da1549fa8a49e350bf3df484?tpId=13&tqId=11183&tPage=2&rp=3&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking
参考这个:c++策略类编程问题汇总 之中求股票最大值的算法
https://blog.csdn.net/weixin_36474809/article/details/100170310
#include
#include
#include
using namespace std;
class Solution {
public:
int FindGreatestSumOfSubArray(vector array) {
int length = array.size();
if (length < 1)return 0;
for (int idx = 1; idx < length; idx++){
array[idx] += array[idx - 1];
}
int min = 0;
int max = array[0];
for (int idx = 1; idx < length; idx++){
int sum = array[idx] - min;
if (sum>max)max = sum;
if (array[idx] < min)min = array[idx];
}
return max;
}
};
int main(){
vector array = { 6, -3, -2, 7, -15, 1, 2, 2 }; //out 8
Solution s1;
cout << s1.FindGreatestSumOfSubArray(array) << endl;
int end; cin >> end;
return 0;
}
一个值用于存最大数值,另一个用于存当前sum,从左往右,如果前面sum小于0,则对于右边来说,最大的右边的子序列必然不包含其左边的项。
这种方法显然比上种方法简单很多:
class Solution {
public:
int FindGreatestSumOfSubArray(vector array) {
int length = array.size();
if (length < 1)return 0;
int max=0x80000000;
int sum = 0;
for (int idx = 0; idx < length; idx++){
if (sum < 0)sum = array[idx];
else sum += array[idx];
if (max
可以从动态规划的角度来理解上面的问题
程序写法与上面一样。
博客:
https://blog.csdn.net/qq_41929449/article/details/79892086
OJ链接:
ZOJ Problem Set - 1074
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1074
https://zoj.pintia.cn/problem-sets/91827364500/problems/91827364573
来自
解析:
https://www.cnblogs.com/aabbcc/p/6504605.html
一个M*N的矩阵,找到此矩阵的一个子矩阵,并且这个子矩阵的元素的和是最大的,输出这个最大的值。
例如:3*3的矩阵:
3
-1 3 -1
2 -1 3
-3 1 2
和最大的子矩阵是:
3 -1
-1 3
1 2
最大和是7
As an example, the maximal sub-rectangle of the array:
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
仅仅例程可以通过,想法不错,但是仔细推导,发现错了
采用了积分图的方法,例程通过,但是OJ不过。吐槽下ZOJ,无法看到中间结果。
#include
#include
#include
#include
using namespace std;
int main(){
int row, col; cin >> row; col = row;
vector each_col(col + 1);
vector> matrix(row + 1, each_col);
vector> min_matrix = matrix;
//算积分图,为了方便运算,第0行和第0列设为0,从1-row分别表示矩阵中的值
//每个像素点的值是其左边和上边所有元素的和
int max_value = 0;
//转换为求其右上元素减去左下元素的最大值
for (int idx_r = 1; idx_r <= row; idx_r++){
for (int idx_c = 1; idx_c <= col; idx_c++){
int current; cin >> current;
matrix[idx_r][idx_c] = matrix[idx_r - 1][idx_c] + matrix[idx_r][idx_c - 1] - matrix[idx_r - 1][idx_c - 1] + current;
min_matrix[idx_r][idx_c] = min(matrix[idx_r][idx_c], min(min_matrix[idx_r - 1][idx_c], min_matrix[idx_r][idx_c - 1]));
int sub_max = matrix[idx_r][idx_c] - min_matrix[idx_r][idx_c];
if (sub_max>max_value)max_value = sub_max;
}
}
cout << max_value << endl;
int end; cin >> end;
return 0;
}
如果对每个子矩阵进行求和比较,需要O((M*N)^2)的算法复杂度。显然不能满足要求
以下代码完全通过
#include
#include
#include
#include
using namespace std;
int main(){
int row, col; cin >> row; col = row;
vector each_row(col);
vector> matrix(row, each_row);
for (int idx_r = 0; idx_r < row; idx_r++){
for (int idx_c = 0; idx_c < col; idx_c++){
cin >> matrix[idx_r][idx_c];
}
}
int max_value = matrix[0][0];
//先将当前up_row到down_row的和存为一维数组,然后在一维数组上寻找
for (int up_row = 0; up_row < row; up_row++){
for (int down_row = up_row; down_row < row; down_row++){
vector row_sum(col, 0);
for (int idx_r = up_row; idx_r <= down_row; idx_r++){
for (int idx_c = 0; idx_c < col; idx_c++){
row_sum[idx_c] += matrix[idx_r][idx_c];
}
}
int sum = row_sum[0];
for (int idx_c = 1; idx_c < col; idx_c++){
if (sum < 0)sum = row_sum[idx_c];
else{
sum += row_sum[idx_c];
}
if (sum>max_value)max_value = sum;
}
}
}
cout << max_value << endl;
int end; cin >> end;
return 0;
}
Leetcode 84。OJ:
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。问脂肪图的最大矩形的面积。
输入
6
2 1 5 6 2 3
输出10
如何根据一遍 遍历O(N)找到当前柱子左边第一个比它矮的柱子?即如何找出每个位置对应的left_min_loc的值。
解答,注意等号的判断。
#include
#include
#include
#include
using namespace std;
class Solution {
public:
int largestRectangleArea(vector& heights) {
int length = heights.size();
if (length < 1)return 0;
vectormost_left_min(length); most_left_min[0] = -1;
vectormost_right_min(length); most_right_min[length - 1] = length;
for (int idx = 1; idx < length; idx++){
int current_height = heights[idx];
if (current_height>heights[idx - 1]){
most_left_min[idx] = idx - 1;
}
else{
int left_min_loc = most_left_min[idx - 1];
while (left_min_loc != -1 && current_height <= heights[left_min_loc]){
left_min_loc = most_left_min[left_min_loc];
}
most_left_min[idx] = left_min_loc;
}
}
//找到最右
for (int idx = length - 2; idx >= 0; idx--){
int current_height = heights[idx];
if (current_height>heights[idx + 1]){
most_right_min[idx] = idx + 1;
}
else{
int right_min_loc = most_right_min[idx + 1];
while (right_min_loc != length && current_height <= heights[right_min_loc]){
right_min_loc = most_right_min[right_min_loc];
}
most_right_min[idx] = right_min_loc;
}
}
int max_square = 0;
for (int idx = 0; idx < length; idx++){
int square = (most_right_min[idx] - most_left_min[idx] - 1)*heights[idx];
if (square>max_square)max_square = square;
}
return max_square;
}
};
int main(){
/*
6
2 1 5 6 2 3
//out 10
12
0 1 0 2 1 0 1 3 2 1 2 1
out 6
*/
int length; cin >> length;
vector height(length);
for (int idx = 0; idx < length; idx++){
cin >> height[idx];
}
Solution s1;
cout << s1.largestRectangleArea(height) << endl;
//cout << max_value << endl;
int end; cin >> end;
return 0;
}
https://blog.csdn.net/huanghanqian/article/details/78771558
Leetcode 85 困难题
OJ:
https://leetcode-cn.com/problems/maximal-rectangle/
给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。例如,输入:
4 5
10100
10111
11111
10010
输出: 6
如果只确定左上右下的矩阵边,则需要对左上和右下进行遍历,算法复杂度O(MN*MN)
#include
#include
#include
#include
using namespace std;
class Solution {
public:
int maximalRectangle(vector>& matrix) {
int row = matrix.size();
if (row < 1)return 0;
int col = matrix[0].size();
int max_num1 = 0;
for (int upper_row = 0; upper_row < row; upper_row++){
for (int lower_row = upper_row; lower_row < row; lower_row++){
vectorcompresed_row(col, '1');
int row_width = lower_row - upper_row + 1;
// 把矩阵投影到每一行,均为1才是1
for (int idx = upper_row; idx <= lower_row; idx++){
for (int idxc = 0; idxc < col; idxc++){
if (matrix[idx][idxc] == '0')compresed_row[idxc] = '0';
}
}
// 针对每一行的投影,算出行宽度
int col_width = 0;
for (int idx = 0; idx < col; idx++){
//矩阵存在,则将最大面积存入max_num1之中
if (compresed_row[idx] == '1'){
col_width++;
if (col_width*row_width>max_num1)max_num1 = col_width*row_width;
}
else{
col_width = 0;
}
}
}
}
return max_num1;
}
};
int main(){
/*
4 5
10100
10111
11111
10010
out 6
5 5
11111
11111
11110
11111
11111
//out 20
*/
int row, col; cin >> row >> col;
vectoreach_row(col);
vector>matrix(row, each_row);
for (int idx = 0; idx < row; idx++){
for (int idxc = 0; idxc < col; idxc++){
cin >> matrix[idx][idxc];
}
}
Solution s1;
cout << s1.maximalRectangle(matrix) << endl;
//cout << max_value << endl;
int end; cin >> end;
return 0;
}
#include
#include
#include
#include
using namespace std;
class Solution {
public:
int maximalRectangle(vector>& matrix) {
int row = matrix.size();
if (row < 1)return 0;
int col = matrix[0].size();
if (col < 1)return 0;
int max_area = 0;
for (int idx_r = 0; idx_r < row; idx_r++){
vector col_tall(col, 0);
//cout << "row_hist_gram:" << idx_r << endl;
//cout << "col_tall" << endl;
for (int idx_c = 0; idx_c < col; idx_c++){
//统计出来当前行往上的直方图
for (int tall_r = idx_r; tall_r < row; tall_r++){
if (matrix[tall_r][idx_c] == '1')col_tall[idx_c]++;
else{
//cout << col_tall[idx_c] << " ";
break;
}
}
}
//cout << endl;
vectorleft_min_loc(col); left_min_loc[0] = -1;
vectorright_min_loc(col); right_min_loc[col - 1] = col;
//从左向右遍历
//cout << "left_min_loc:";
for (int idx = 1; idx < col; idx++){
int current_height = col_tall[idx];
//比左边大,则左边位置即为left_min_loc
if (current_height>col_tall[idx - 1]){
left_min_loc[idx] = idx - 1;
}
else{// <= 左边,则可以左边再向左延申
int current_left_loc = idx - 1;
while (current_left_loc != -1 && current_height <= col_tall[current_left_loc]){
current_left_loc = left_min_loc[current_left_loc];
}
left_min_loc[idx] = current_left_loc;
}
//cout << left_min_loc[idx] << ' ';
}
//cout << endl;
//从右向左遍历
//cout << "right_min_loc:";
for (int idx = col - 2; idx >= 0; idx--){
int current_height = col_tall[idx];
//比右边大,则右边位置即为right_min_loc
if (current_height>col_tall[idx + 1]){
right_min_loc[idx] = idx + 1;
}
else{// <= 右边,则可以右边再向右延申
int current_right_loc = idx + 1;
while (current_right_loc != col && current_height <= col_tall[current_right_loc]){
current_right_loc = right_min_loc[current_right_loc];
}
right_min_loc[idx] = current_right_loc;
}
//cout << right_min_loc[idx] << ' ';
}
//cout << endl;
for (int idx = 0; idx < col; idx++){
int area = (right_min_loc[idx] - left_min_loc[idx] - 1)*col_tall[idx];
//cout << area << ' ';
if (area>max_area)max_area = area;
}
}
//cout << endl;
return max_area;
}
};
int main(){
/*
4 5
10100
10111
11111
10010
out 6
5 5
11111
11111
11110
11111
11111
//out 20
*/
int row, col; cin >> row >> col;
vectoreach_row(col);
vector>matrix(row, each_row);
for (int idx = 0; idx < row; idx++){
for (int idxc = 0; idxc < col; idxc++){
cin >> matrix[idx][idxc];
}
}
Solution s1;
cout << s1.maximalRectangle(matrix) << endl;
int end; cin >> end;
return 0;
}