Leetcode 77
题目的第一想法:
这道题的要求是穷尽一些数字的组合,需要注意的是数字的位置并不重要,因此,(1,2)和(2,1)算是同一个项。这道题应该算是回溯的模板了。基本上需要注意的是回溯需要的一些variable。比如开始的数值,在recurrsion里面使用的for循环都算是所谓的回溯法“公式”中的一环。还有必要是的一些trim的操作。另外,leetcode上的提供的最快写法实际上是可以只使用recursion来写的。
class Solution {
List<List<Integer>> rlist = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> rlist = new LinkedList<>();
List<Integer> tempList = new LinkedList<>();
combine(1, n, k, tempList, rlist);
return rlist;
}
public void combine(int start, int n, int k, List<Integer> temp, List<List<Integer>> rlist){
if(temp.size() == k){
rlist.add(new LinkedList<>(temp));
return;
}else{
for(int i = start; i <= n - (k - temp.size()) + 1; i++){
temp.add(i);
combine(i + 1, n, k, temp, rlist);
temp.remove(temp.size() - 1);
}
}
}
}
看完代码随想录之后的想法:
这里修剪的逻辑是,在某一个回溯的某一个时刻。会出现哪怕穷尽接下来所有的组合,也无法满足结果放入返回的表里面的情况。此时,我们可以把这些无用的操作通过条件的判断来裁剪掉。
Leetcode 216
题目的第一想法:
这道题的要求是在一些数字中找到k个数字相加=n。其中k和n是以知的。这道题和上一道题的区别是停止条件的不同。因为我们需要找到相加=n的组合。所以还需要一个sum。在每次移除或添加数字时也要对sum进行相应的操作(+= || -=)。其余的和77题一样。
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<Integer> list = new LinkedList<>();
List<List<Integer>> rlist = new LinkedList<>();
backTracking(k, n, 1, list, rlist, 0);
return rlist;
}
public void backTracking(int k, int n, int start, List<Integer> list, List<List<Integer>> rlist, int sum){
if(list.size() == k && sum == n){
rlist.add(new LinkedList<>(list));
return;
}
for(int i = start; i <= 9; i++){
if(i > n) return;
else if(k - list.size() >= 9 - i + 2) return;
list.add(i);
sum += i;
backTracking(k, n, i + 1, list, rlist, sum);
sum -= i;
list.remove(list.size() - 1);
}
}
}
看完代码随想录之后的想法:
记得trim
Leetcode 17
题目的第一想法:
这道题的要求给出几个九宫格上的数字。找到这几个数字这道题我的第一想法是使用两个for loop,一个用来遍历当前的数字,另一个则用来遍历每个数字的字母。但直接使用两个for loop的问题是,第二个数字内的字母会和自己重复。原因在于在最初的loop中,我并没能找到一个合理的条件来只停止最初的for loop。因为所有的递归都使用同样的结构。所以很难只停止其中的某一个for loop。
class Solution {
HashMap<Character, String> match = new HashMap<>(){{
put('0', "");
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
put('1', "");
}
};
public List<String> letterCombinations(String digits) {
List<String> rlist = new LinkedList<>();
StringBuilder st = new StringBuilder();
StringBuilder dd = new StringBuilder(digits);
if(digits.isEmpty()) return rlist;
backTracking(0, st, dd, rlist);
return rlist;
}
public void backTracking(int start, StringBuilder st, StringBuilder digits, List<String> rlist){
if(start == digits.length()){
rlist.add(st.toString());
return;
}
for(int j = 0; j < match.get(digits.charAt(start)).length(); j++){
st.append(match.get(digits.charAt(start)).charAt(j));
backTracking(start + 1, st, digits, rlist);
st.deleteCharAt(st.length() - 1);
}
}
}
看完代码随想录之后的想法:
这个逻辑还是很酷的。使用一个递归来传递字母,for loop来传递组合。