leetcode39:组合总和

题目链接

leetcode

题目描述

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的所有 不同组合,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

C++ 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

/*
回溯,深度优先搜索 DFS

时间复杂度:O(2^n)
其中 n 是候选数字的数量。
在最坏的情况下,每个数字都有两种选择:选择或不选择,共有 2^n 种组合。
空间复杂度:O(m)
其中 m 是结果列表中元素的平均长度。
*/
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
if (candidates.empty()) {
return result;
}

backtracking(candidates, target, 0, 0);

return result;
}

void backtracking(vector<int>& candidates, int target, int sum, int start) {
// 剪枝条件:超过目标和
if (sum > target) {
return;
}
// 结束条件:找到目标和
if (sum == target) {
result.push_back(path);
return;
}

for (int i = start; i < candidates.size(); i++) {
// 选择
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i); // 不用i+1,表示可以重复读取当前的数字
// 撤销选择:回溯
sum -= candidates[i];
path.pop_back();
}
}

private:
vector<vector<int>> result;
vector<int> path;
};

/*
前一个版本的代码,对于 sum 大于 target 情况,仍然进入了下一层递归,
下一层递归结束的时候,判断 sum > target 才返回。

如果已知下一层 sum 大于 target,就没有必要进入下一层递归,
可以在 for 循环时候进行限制。
*/
class Solution_1 {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
if (candidates.empty()) {
return result;
}

sort(candidates.begin(), candidates.end()); // 排序,数组的有序性来提前终止不必要的递归
backtracking(candidates, target, 0, 0);

return result;
}

void backtracking(vector<int>& candidates, int target, int sum, int start) {
// 结束条件:找到目标和
if (sum == target) {
result.push_back(path);
return;
}

for (int i = start; i < candidates.size(); i++) {
// 剪枝条件:超过目标和
if (sum + candidates[i] > target) {
break;
}

// 选择
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i); // 不用i+1,表示可以重复读取当前的数字
// 撤销选择:回溯
sum -= candidates[i];
path.pop_back();
}
}

private:
vector<vector<int>> result;
vector<int> path;
};

// 辅助函数:打印数组
void printArray(vector<int>& nums) {
cout << "[";
for (size_t i = 0; i < nums.size(); i++) {
cout << nums[i];
if (i != nums.size()-1) {
cout << ",";
}
}
cout << "]";
}

// 辅助函数:打印二维数组
void printArray(const vector<vector<int>>& nums) {
cout << "[";
for (size_t i = 0; i < nums.size(); i++) {
cout << "[";
for (size_t j = 0; j < nums[i].size(); j++) {
cout << nums[i][j];
if (j != nums[i].size() - 1) cout << ",";
}
cout << "]";
if (i != nums.size() - 1) cout << ",";
}
cout << "]";
}

int main() {
Solution solution;
vector<vector<int>> candidates_cases = {
{2,3,6,7},
{2,3,5},
{2}
};
vector<int> target_cases = {
7, 8, 1
};

for (size_t i = 0; i < candidates_cases.size(); i++) {
auto& candidates = candidates_cases[i];
int target = target_cases[i];

cout << "Input: candidates = ";
printArray(candidates);
cout << ", target = " << target << endl;

vector<vector<int>> result = solution.combinationSum(candidates, target);
cout << "Output: ";
printArray(result);
cout << endl;
}

return 0;
}

leetcode39:组合总和
https://lcf163.github.io/2023/10/20/leetcode39:组合总和/
作者
乘风的小站
发布于
2023年10月20日
许可协议