很高兴又坚持了7天。
算法(回溯)
class Solution {
List<Integer> list = new LinkedList<>();
List<List<Integer>> llist = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
back(n,k,1);
return llist;
}
public void back(int n,int k,int index){
if(list.size() == k){
llist.add(new LinkedList<>(list));
return;
}
//剪枝优化:举个例子,当n=k的时候,很明显路只有一条,因此后面的都无需再遍历
//剪枝从什么角度入手去考虑呢?
for(int i = index;i<=(n - (k-list.size()) + 1);i++){
list.add(i);
back(n,k,i+1);
list.remove(list.size()-1);
}
}
}
class Solution {
List<List<Integer>> res;
List<Integer> list;
public List<List<Integer>> combinationSum3(int k, int n) {
res = new ArrayList<>();
list = new ArrayList<>();
back(k,n,1,0);
return res;
}
public void back(int k,int n,int index,int sum){
//剪枝
if(sum > n){
return;
}
//终止条件
if(list.size() == k){
if(sum == n){
res.add(new ArrayList<>(list));
}
return;
}
//剪枝:如果当前和已经大于目标值,很显然没必要继续遍历
for(int i = index;i<=9;i++){
if(sum+i > n){
continue;
}
sum+=i;
list.add(i);
back(k,n,i+1,sum);
sum-=i;
list.remove(list.size()-1);
}
}
}
class Solution {
//设置全局列表存储最后的结果
List<String> list = new ArrayList<>();
String[] num = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public List<String> letterCombinations(String digits) {
if(digits.equals("") || digits == null) return list;
back(digits,0);
return list;
}
StringBuilder tmp = new StringBuilder();
public void back(String digits,int index){
//终止条件
if(index == digits.length()){
list.add(tmp.toString());
return;
}
//通过index找到当前按下的键
String now = num[digits.charAt(index)-'0'];
//遍历可能的组合
for(int i = 0;i<now.length();i++){
tmp.append(now.charAt(i));
back(digits,index+1);
tmp.deleteCharAt(tmp.length()-1);
}
}
}
class Solution {
List<List<Integer>> res;//大结果集
List<Integer> list;//小结果集
public List<List<Integer>> combinationSum(int[] candidates, int target) {
res = new ArrayList<>();
list = new ArrayList<>();
//排序
Arrays.sort(candidates);
back(candidates,target,0,0);
return res;
}
public void back(int[] candidates,int tar,int idx,int sum){
if(sum == tar){
res.add(new ArrayList<>(list));
return;
}
for(int i = idx;i<candidates.length;i++){
if(sum + candidates[i] > tar){
continue;
}
sum+=candidates[i];
list.add(candidates[i]);
back(candidates,tar,i,sum);
list.remove(list.size()-1);
sum-=candidates[i];
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
//利用一个数组来记录某数字是否被使用过
boolean[] used;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.sort(candidates);
Arrays.fill(used,false);
back(candidates,target,0,0);
return res;
}
public void back(int[] candidates, int target,int sum,int idx){
if(sum == target){
res.add(new LinkedList<>(list));
return;
}
for(int i = idx;i<candidates.length;i++){
//剪枝
if(sum + candidates[i] > target) continue;
//当前位和前一位相同的情况下,如果前一位已经为false,说明已经被选择过了,跳过
if(i>0 && candidates[i]==candidates[i-1] && used[i-1] == false){
continue;
}
sum+=candidates[i];
list.add(candidates[i]);
used[i] = true;
back(candidates,target,sum,i+1);
used[i] = false;
list.remove(list.size()-1);
sum-=candidates[i];
}
}
}
class Solution {
List<List<String>> res = new ArrayList<>();
List<String> list;
public List<List<String>> partition(String s) {
list = new ArrayList<>();
back(s,0);
return res;
}
public void back(String s,int idx){
//如果idx到/超过了s的长度说明已经可以加入集合了
if(idx >= s.length()){
res.add(new ArrayList<>(list));
return;
}
for(int i = idx;i<s.length();i++){
if(isValid(idx,i,s)){
//当前区间是回文串
String tmp = s.substring(idx,i+1);
list.add(tmp);
back(s,i+1);
list.remove(list.size()-1);
}else{
continue;
}
}
}
//判断是否为回文串
public boolean isValid(int start,int end,String s){
while(start<end){
if(s.charAt(start) != s.charAt(end)) return false;
start++;
end--;
}
return true;
}
}
思考
剪枝从什么角度去入手呢?
剩余的数量是否足够我去凑成结果集
剩余的数量还有没有必要让我继续去跑下一轮来选择?
补充知识点
今天无知识点的补充,明天出发去北京啦