Leetcode 回溯法欣赏,助你发现其中套路(部分内容引自评论区)
Subsets : https://leetcode.com/problems/subsets/
题目:
Input: nums = [1,2,3]
Output:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
代码:
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}
Subsets II (contains duplicates) : https://leetcode.com/problems/subsets-ii/
题目:
Input: [1,2,2]
Output:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
代码:
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}
Permutations : https://leetcode.com/problems/permutations/
题目:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
代码:
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
// Arrays.sort(nums); // not necessary
backtrack(list, new ArrayList<>(), nums);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(tempList.contains(nums[i])) continue; // element already exists, skip
tempList.add(nums[i]);
backtrack(list, tempList, nums);
tempList.remove(tempList.size() - 1);
}
}
}
Permutations II (contains duplicates) : https://leetcode.com/problems/permutations-ii/
题目:
Input: [1,1,2]
Output:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
代码:
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, boolean [] used){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;
used[i] = true;
tempList.add(nums[i]);
backtrack(list, tempList, nums, used);
used[i] = false;
tempList.remove(tempList.size() - 1);
}
}
}
https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&tqId=11180&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目:(字符串的排列 )
题目描述
:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述
:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
代码:
/*
回溯法
思路:
把字符串分成2部分,第一部分只占一位,后面的为第二部分
让第一部分,与第二部的字符串交换位置(即找到第一位所有的可能)
固定第一位,把 同样的方法 作用于 第二部分
*/
ArrayList<String> res=new ArrayList<>();
public ArrayList<String> Permutation(String str) {
if(str==null||str.length()==0)
return res;
backTrack(str.toCharArray(),0);
Collections.sort(res);
return res;
}
/*
* i表示让第几位与后面的字符们交换位置,然后固定第几位的字符
* 直到i==chars.length,代表整个字符串每一位的字符都固定了,这时判断字符串是否在res中,不在则加入到res中
* */
private void backTrack(char[] chars, int i) {
if(i==chars.length-1){
String str=String.valueOf(chars);
if(!res.contains(str)){
res.add(str);
}
}else{
for (int j=i;j<chars.length;j++){
if(j==i||chars[i]!=chars[j]){
swapChar(chars,i,j);
//注意:这里递归调用的参数应该是i+1,固定i后面的字符
backTrack(chars,i+1);
swapChar(chars,i,j);
}
}
}
}
private void swapChar(char[] chars, int i, int j) {
char c=chars[i];
chars[i]=chars[j];
chars[j]=c;
}
题目:
输入:
abc
输出:
a,ab,abc,ac,b,bc,c
代码:
ArrayList<String> res=new ArrayList<>();
public ArrayList<String> Permutation(String str) {
if(str==null||str.length()==0)
return res;
backTrack(str.toCharArray(),new StringBuilder(),0);
return res;
}
private void backTrack(char[] chars, StringBuilder sb, int start) {
if(sb.length()!=0){
res.add(sb.toString());
}
for (int i=start;i<chars.length;i++){
sb.append(chars[i]);
//这里的递归调用的参数不能写错哦
backTrack(chars,sb,i+1);
sb.deleteCharAt(sb.length()-1);
}
}
题目:二叉树中和为某一值的路径
https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?tpId=13&&tqId=11177&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
代码:
//经典的回溯法
ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
public ArrayList<ArrayList<Integer>> FindPath1(TreeNode root, int target) {
if(root==null||target==0)
return res;
backTrack(root,target,new ArrayList<Integer>());
return res;
}
private void backTrack(TreeNode root, int target, ArrayList<Integer> list) {
if(root.left==null&&root.right==null){
if(root.val==target){
list.add(root.val);
res.add(new ArrayList<>(list));
list.remove(list.size()-1);
}
}else{
if((target-root.val)<=0){
return;
}
list.add(root.val);
if(root.left!=null){
backTrack(root.left,target-root.val,list);
}
if(root.right!=null){
backTrack(root.right,target-root.val,list);
}
list.remove(list.size()-1);
}
}