List result = new ArrayList();
public void backtrack(路径, 选择列表){
if(满足结束条件){
result.add(路径);
return;
}
for(选择 : 选择列表){ //层序遍历
做选择;
backtrack(路径, 选择列表); //递归遍历
撤销选择;
}
}
组合是无序的,即{1,2}与{2,1}是同一个组合。
class Solution {
public List<Integer> path = new LinkedList<>();
public List<List<Integer>> ansList = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
//首先确定回溯法构造的树的根下面第一层是n个节点,即for循环的判别条件是<=n
//终止条件是每条路径包含k个元素
//需要进行剪枝,当剩余元素无法满足path.size()==k,是推出循环
backtrack(n,k,1);
return ansList;
}
public void backtrack(int n, int k, int index){
if(path.size() == k){
ansList.add(new ArrayList<>(path));//不能直接将path加入anList,因为path是引用类型
return;
}
for (int i = index; i <= n-(k-path.size())+1; i++) {
path.add(i);
backtrack(n,k,i+1);
path.removeLast();
}
}
}
class Solution {
public List<Integer> path = new LinkedList<>();
public List<List<Integer>> ansList = new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
//终止条件是path中包含k个数
//构造的树的根下面的第一层包含[1,9]
backtrack(k,n,1);
return ansList;
}
public void backtrack(int k,int n,int index){
if(path.size()==k){
int sums = 0;
for (int i = 0; i < k; i++) {
sums += path.get(i);
}
if(sums == n){
ansList.add(new ArrayList<>(path));
}
return;
}
for (int i = index; i <= 9-(k-path.size())+1 ; i++) {
path.add(i);
backtrack(k,n,i+1);
path.removeLast();
}
}
}
class Solution {
public List<String> ansList = new ArrayList<>();
public StringBuilder path = new StringBuilder();
HashMap<Character,String> map = new HashMap<>();
public List<String> letterCombinations(String digits) {
//首先使用map存储每个数字对应的字符串
//这里的循环需要进行次数为每个输入数字所表示的字符串的长度
//递归次数为输入数字字符串的长度
if(digits.length() == 0) return new ArrayList<>();
map.put('2',"abc");
map.put('3',"def");
map.put('4',"ghi");
map.put('5',"jkl");
map.put('6',"mno");
map.put('7',"pqrs");
map.put('8',"tuv");
map.put('9',"wxyz");
backtrack(digits,digits.length(),0);
return ansList;
}
public void backtrack(String digits,int len,int index){
//终止条件是path里有len个字符
if(path.length() == len){
ansList.add(path.toString());
return;
}
String s = map.get(digits.charAt(index));
for (int i = 0; i < s.length(); i++) {
path.append(s.charAt(i));
backtrack(digits,len,index+1);
path.deleteCharAt(path.length()-1);
}
}
}
class Solution {
public List<List<Integer>> ansList = new ArrayList<>();
public List<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
//本题的特点是不限制元素出现次数,组合的数量
//因此,终止条件就为sum>=target
//另外为了提高效率,在循环时进行剪枝,需要对数组进行排序
Arrays.sort(candidates);
backtrack(candidates,target,0,0);
return ansList;
}
public void backtrack(int[] candidates, int target, int sum,int index){
if(sum == target){
ansList.add(new ArrayList<>(path));
return;
}
for (int i = index; i<candidates.length && sum+candidates[i]<=target; i++) {
sum += candidates[i];
path.add(candidates[i]);
backtrack(candidates,target,sum,i);
sum -= path.get(path.size()-1);
path.removeLast();
}
}
}
class Solution {
public List<List<Integer>> ansList = new ArrayList<>();
public List<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//本题的与上一题的区别是每个元素只能出现一次
//因此在排序之后,循环时需要跳过相同的元素
//并不是所有遇到相同元素的情况就要跳过
//只有两个节点属于同一递归深度时才跳过
Arrays.sort(candidates);
backtrack(candidates,target,0,0);
return ansList;
}
public void backtrack(int[] candidates,int target,int sum,int index){
if(sum == target){
ansList.add(new ArrayList<>(path));
return;
}
for(int i=index;i<candidates.length && sum+candidates[i]<=target;i++){
if(i>index && candidates[i] == candidates[i-1]) continue;
sum += candidates[i];
path.add(candidates[i]);
backtrack(candidates,target,sum,i+1);
sum -= path.get(path.size()-1);
path.removeLast();
}
}
}
class Solution {
List<List<String>> ansList = new ArrayList<>();
List<String> path = new LinkedList<>();
public List<List<String>> partition(String s) {
//第i层选取从第i个元素为起始点进行分割,
//因此,需要记录每次进行分割的起始点
//递归时要将起始点+1
//每次分割都要判断当前部分是否满足回文串的要求
//终止条件是起始点到最后一个元素
backtrack(s,0);
return ansList;
}
public void backtrack(String s,int index){
if(index >= s.length()){
ansList.add(new ArrayList<>(path));
return;
}
for(int i=index;i<s.length();i++){
String subStr = s.substring(index,i+1);
if(!isPalindrome(subStr)){
continue;
}else{
path.add(subStr);
}
backtrack(s,i+1);
path.removeLast();
}
}
public boolean isPalindrome(String str){
for (int i = 0, j=str.length()-1; i < j; i++,j--) {
if(str.charAt(i) != str.charAt(j)){
return false;
}
}
return true;
}
}
class Solution {
public List<String> ansList = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
//和上一题相似,需要对字符串进行分割
//终止条件是出现了3个.,即分割3次
backtrack(s,0,0);
return ansList;
}
public void backtrack(String s, int index, int pointNum){
if(pointNum == 3){
if(isValid(s.substring(index))){
ansList.add(s);
}
return;
}
for (int i = index; i < s.length(); i++) {
String str = s.substring(index,i+1);
if(!isValid(str) || i+1==s.length()){
break;
}else{
str = s.substring(0,i+1)+"."+s.substring(i+1);
pointNum++;
backtrack(str,i+2,pointNum);
pointNum--;
str = s.substring(0,i+1)+s.substring(i+2);
}
}
}
public boolean isValid(String subStr){
if(subStr.length()>3 || subStr==""){
return false;
}
if(subStr.length()>1 && subStr.charAt(0)=='0'){
return false;
}
int i = Integer.parseInt(subStr);
if(i>255){
return false;
}
return true;
}
}
class Solution {
public List<List<Integer>> ansList = new ArrayList<>();
public List<Integer> subSet = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
//寻找所有子集,意味着需要记录所有节点的值
ansList.add(new ArrayList<>(subSet));
backtrack(nums,0);
return ansList;
}
public void backtrack(int[] nums,int index){
if(index >= nums.length){
return;
}
for (int i = index; i < nums.length; i++) {
subSet.add(nums[i]);
ansList.add(new ArrayList<>(subSet));
backtrack(nums,i+1);
subSet.removeLast();
}
}
}
class Solution {
public List<List<Integer>> ansList = new ArrayList<>();
public List<Integer> subSet = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
//本题与上一题的区别是有重复元素
//因此需要对数组进行排序
Arrays.sort(nums);
ansList.add(new ArrayList<>(subSet));
backtrack(nums,0);
return ansList;
}
public void backtrack(int[] nums,int index){
if(index == nums.length){
return;
}
for (int i = index; i < nums.length; i++) {
if(i!=index && nums[i] == nums[i-1]){
continue;
}
subSet.add(nums[i]);
ansList.add(new ArrayList<>(subSet));
backtrack(nums,i+1);
subSet.removeLast();
}
}
}
class Solution {
List<List<Integer>> ansList = new ArrayList<>();
List<Integer> subSet = new LinkedList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
//注意题中要求子序列至少有2个元素
//数组中有重复元素,所以在同一递归层要判断改元素之前是否使用过
//可以使用map和数组,因为这里数组的值在[-100,100]
//所以这里使用数组记录某一递归层是否使用过某一元素
backtrack(nums,0);
return ansList;
}
public void backtrack(int[] nums, int index){
if(subSet.size() > 1) {
ansList.add(new ArrayList<>(subSet));
}
int[] used = new int[201];
for(int i=index;i<nums.length;i++){
if(used[nums[i]+100] == 1) continue;
if(!subSet.isEmpty() && subSet.get(subSet.size()-1)>nums[i]){
continue;
}
subSet.add(nums[i]);
used[nums[i]+100] = 1;
backtrack(nums,i+1);
subSet.removeLast();
}
}
}