目录
1. T77:组合
T77:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
提示:
-
1 <= n <= 20
-
1 <= k <= n
S:
以n、k和当前层起始计数(从1开始)为参数,组合中 元素个数 == k 为终止条件,不设置局部返回值
如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了
C++:
vector<vector<int>> combine(int n, int k) {
backtracking(n, k, 1);
return res;
}
private:
vector<vector<int>> res;
vector<int> path;
void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
res.push_back(path);
return;
}
// for (int i = startIndex; i <= n; ++i) {
for (int i = startIndex; i <= n - (k - path.size()) + 1; ++i) {
path.push_back(i);
backtracking(n, k, i + 1);
path.pop_back();
}
}
Java:
List<List<Integer>> res;
// List<Integer> path;
LinkedList<Integer> path;
public List<List<Integer>> combine(int n, int k) {
res = new ArrayList<>();
path = new LinkedList<>();//最初有点怀疑:这里的初始化是否能传入backtracking🚩——能!
backtracking(n, k, 1);
return res;
}
private void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
// res.add(path);
res.add(new ArrayList<>(path));
return;
}
// for (int i = startIndex; i <= n; ++i) {
for (int i = startIndex; i <= n - (k - path.size()) + 1; ++i) {
path.add(i);
backtracking(n, k, i + 1);
// path.remove(path.size() - 1);
path.removeLast();
}
}
2. T216:组合总和Ⅲ
T216:找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
-
只使用数字1到9
-
每个数字 最多使用一次
-
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
提示:
-
2 <= k <= 9
-
1 <= n <= 60
S:跟上一题一样的套路,就是终止条件不同
C++:本来是按照下面写的(能通过),但看了题解才意识到求和的过程也可以回溯~
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k, n, 1);
return res;
}
private:
vector<vector<int>> res;
vector<int> path;
void backtracking(int k, int n, int startIndex) {
if (path.size() == k) {
if (getPathSum(path) == n) {
res.push_back(path);
// return;//栈溢出
}
return;//🚩无论是否符合都要return
}
for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {
path.push_back(i);
backtracking(k, n, i + 1);
path.pop_back();
}
}
int getPathSum(vector<int> path) {
int sum = 0;
for (int i = 0; i < path.size(); ++i) {
sum += path[i];
}
return sum;
}
求和回溯:
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k, n, 0, 1);
return res;
}
private:
vector<vector<int>> res;
vector<int> path;
void backtracking(int k, int n, int sum, int startIndex) {
if (path.size() == k) {
// if (getPathSum(path) == n) {
if (sum == n) {
res.push_back(path);
// return;//在这里return->栈溢出
}
return;//无论是否符合都要return
}
for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {
path.push_back(i);
backtracking(k, n, sum + i, i + 1);//隐式回溯
path.pop_back();
}
}
Java:
List<List<Integer>> res;
LinkedList<Integer> path;
public List<List<Integer>> combinationSum3(int k, int n) {
res = new ArrayList<>();
if (n == 0 || k == 0) return res;
path = new LinkedList<>();//🚩要是没有初始化,下面.size()->NullPointerException
backtracking(k, n, 0, 1);
return res;
}
private void backtracking(int k, int targetSum, int sum, int startIndex) {
if (path.size() == k) {
if (sum == targetSum) {
res.add(new LinkedList<>(path));//必须申请新的内存空间,否则都是指向同一个对象,插入结果集后又变了
}
return;
}
for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {
path.add(i);
backtracking(k, targetSum, sum + i, i + 1);
path.removeLast();
}
}
3. T17:电话号码的字母组合
T17:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
提示:
-
0 <= digits.length <= 4
-
digits[i] 是范围 ['2', '9'] 的一个数字。
S:自己试着敲了一遍,通过了,但还要优化
C++:
【self】下面这版虽然能通过,但是存在问题:嵌套for循环和递归终止条件功能重叠
vector<string> res;
string combination;
vector<string> letterCombinations(string digits) {
if (digits.size() == 0) return res;
backtracking(digits, digits.size(), 0);
return res;
}
private:
void backtracking(const string& digits, int length, int startIndex) {//也可以不要const和&
if (combination.size() == length) {
res.push_back(combination);
return;
}
for (int i = startIndex; i < digits.size(); ++i) {
int curNum = digits[i] - '0';
string curLetters = letterMap[curNum];
for (int j = 0; j < curLetters.size(); ++j) {
combination.push_back(curLetters[j]);
// backtracking(digits, length, startIndex + 1);//一度又犯傻!
backtracking(digits, length, i + 1);
combination.pop_back();
}
}
}
const string letterMap[10] = {
"",//0
"",//1
"abc",//2
"def",
"ghi",//4
"jkl",
"mno",//6
"pqrs",//7
"tuv",
"wxyz"//9
};
3.1 显式回溯
C++:
vector<string> res;
string combination;
vector<string> letterCombinations(string digits) {
if (digits.size() == 0) return res;
backtracking(digits, 0);
return res;
}
private:
void backtracking(string digits, int curIndex) {
if (curIndex == digits.size()) {
res.push_back(combination);
return;
}
int digit = digits[curIndex] - '0';
string curLetters = letterMap[digit];
for (int i = 0; i < curLetters.size(); ++i) {
combination.push_back(curLetters[i]);
// backtracking(digits, i + 1);//🚩栈溢出
backtracking(digits, curIndex + 1);
combination.pop_back();
}
}
Java:
List<String> res;
StringBuilder combination;
public List<String> letterCombinations(String digits) {
res = new ArrayList<>();
if (digits == null || digits.equals("") || digits.length() == 0) return res;
combination = new StringBuilder();
backtracking(digits, 0);
return res;
}
private void backtracking(String digits, int curIndex) {
if (curIndex == digits.length()) {
res.add(combination.toString());
return;
}
// int curNum = curIndex - '0';//犯傻!
int curNum = digits.charAt(curIndex) - '0';
String curLetters = letterMap[curNum];
for (int i = 0; i < curLetters.length(); ++i) {
// combination.append(i);//"00","01"
combination.append(curLetters.charAt(i));
backtracking(digits, curIndex + 1);
combination.deleteCharAt(combination.length() - 1);
}
}
private final String[] letterMap = {
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz"
};
3.2 隐式回溯
C++:
vector<string> res;
// string combination;
vector<string> letterCombinations(string digits) {
if (digits.size() == 0) return res;
backtracking(digits, 0, "");
return res;
}
private:
void backtracking(string digits, int curIndex, string s) {
if (curIndex == digits.size()) {
res.push_back(s);
return;
}
int digit = digits[curIndex] - '0';
string curLetters = letterMap[digit];
for (int i = 0; i < curLetters.size(); ++i) {
backtracking(digits, curIndex + 1, s + curLetters[i]);
}
}
Java:
List<String> res;
public List<String> letterCombinations(String digits) {
res = new ArrayList<>();
if (digits == null || digits.equals("") || digits.length() == 0) return res;
backtracking(digits, 0, "");
return res;
}
private void backtracking(String digits, int curIndex, String s) {
if (curIndex == digits.length()) {
res.add(s);
return;
}
int curNum = digits.charAt(curIndex) - '0';
String curLetters = letterMap[curNum];
for (int i = 0; i < curLetters.length(); ++i) {
backtracking(digits, curIndex + 1, s + curLetters.charAt(i));
}
}