回溯法(backtracking) 題目整理--------part1


回溯法概念:回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。

回溯法是一個既帶有系統性又帶有跳躍性的的搜索算法。它在包含問題的所有解的解空間樹中,按照深度優先的策略,從根結點

出發搜索解空間樹。算法搜索至解空間樹的任一結點時,總是先判斷該結點是否肯定不包含問題的解。如果肯定不包含,則跳過

對以該結點為根的子樹的系統搜索,逐層向其祖先結點回溯。否則,進入該子樹,繼續按深度優先的策略進行搜索。回溯法在用來

求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜索遍才結束。

概念:http://www.cnblogs.com/jiangchen/p/5393849.html

1. Combination Sum

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

 

For example, given candidate set [2, 3, 6, 7] and target 7
A solution set is: 

[
  [7],
  [2, 2, 3]
]

剛做的時候的思路:

用for循環+ 遞歸的方式求解

  for 循環套在外層,表示遍歷數組的第i個數字

  內層遞歸表示結果list里的第i個數字(比如第一層遞歸是尋找list里的第一個數字)

歸納:其實這就是回溯法做的一個dfs,找到第一個節點,然后再找第二個節點,當固定第一個節點的所有解找到后,再換另外個點做為第一個節點。

 1 public class Solution {
 2     public List<List<Integer>> combinationSum(int[] candidates, int target) {
 3         int size = candidates.length;
 4         List<List<Integer>> res = new ArrayList<List<Integer>>();
 5         List<Integer> list = new ArrayList<Integer>();
 6         helper (res, list, candidates, target, 0);
 7         return res;
 8     }
 9     private static void helper(List<List<Integer>> res,List<Integer> list, int[] candidates, int target, int pos) {
10         if (target == 0) {
11             res.add(new ArrayList<Integer>(list));
12             return;
13 
14         } 
15        
16         if (target < 0) {
17             return;
18         }
19         int prev = -1;
20         for (int i = pos; i < candidates.length; i++) {
21             if(prev == candidates[i]) {
22                 continue;
23             }
24             list.add(candidates[i]);
25             helper(res, list, candidates, target - candidates[i], i);
26             prev = candidates[i];
27             list.remove(list.size() - 1);
28         }
29     }
30 }
combination

 ---------------我是分割線--------------------------------------

Combination Sum 2 

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

 

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8
A solution set is: 

[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

這個題目要注意下面的錯誤情況

用遞歸尋找第一個元素時,如果之前的結果里已經把1當作第一個元素,然后pop出去了,那么下次的1再想做為第一個元素的話就直接continue,這樣就避免了2個[1,2,5]的情況,也就是說,在for循環里面不允許有相同的元素!只有第一次出現才做為valid

 1 public class Solution {
 2     public List<List<Integer>> combinationSum2(int[] candidates, int target) {
 3         int size = candidates.length;
 4         Arrays.sort(candidates);
 5         List<List<Integer>> res = new ArrayList<List<Integer>>();
 6         List<Integer> list = new ArrayList<Integer>();
 7         helper (res, list, candidates, target, 0);
 8         return res;
 9     }
10     private static void helper(List<List<Integer>> res,List<Integer> list, int[] candidates, int target, int pos) {
11         if (target == 0) {
12             res.add(new ArrayList<Integer>(list));
13             return;
14 
15         } 
16         if (target < 0) {
17             return;
18         }
19         int prev = -1;
20         for (int i = pos; i < candidates.length; i++) {
21             if (candidates[i] > target) {
22                 break;
23             }
24             
25             if (prev != -1 && prev == candidates[i]) {
26                 continue;
27             }
28             
29             if (candidates[i] != -1) {
30                 list.add(candidates[i]);
31                 helper(res, list, candidates, target - candidates[i], i + 1);
32                 prev = candidates[i];
33                 list.remove(list.size() - 1);
34             }
35         }
36     }
37 }
combinationSum2

 ---------------我是分割線--------------------------------------

 

Combination Sum 3

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.

Example 1:

Input: k = 3, n = 7

Output:

[[1,2,4]]

Example 2:

Input: k = 3, n = 9

Output:

[[1,2,6], [1,3,5], [2,3,4]]

 1 public class Solution {
 2     public List<List<Integer>> combinationSum3(int k, int n) {
 3         List<List<Integer>> res = new ArrayList<List<Integer>>();
 4         List<Integer> list = new ArrayList<Integer>();
 5         helper (res, list, k, n, 1);
 6         return res;
 7     }
 8     private static void helper(List<List<Integer>> res,List<Integer> list, int k, int n, int current) {
 9         if (n == 0 && list.size() == k) {
10             res.add(new ArrayList<Integer>(list));
11             return;
12 
13         } 
14         if (list.size() == k || n < 0) {
15             return;
16         }
17         
18       
19         for (int i = current; i < 10; i++) {
20             list.add(i);
21             helper(res, list, k, n - i, i + 1);
22             list.remove(list.size() - 1);
23         }
24     }
25 }
combinationSum3

相當於[1,2,3,4,5,6,7,8,9] 的數組,然后增加了k的控制條件

 

 ---------------我是分割線--------------------------------------

 

 Combination Sum IV

 

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

Example:

nums = [1, 2, 3]
target = 4

The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.

Therefore the output is 7.

 

Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?

 

巨坑,只需要返回結果個數,那么其實是個動態規划的題目,類似於爬樓梯!!!

就他娘的這么簡單 = = 

 1 public class Solution {
 2     public int combinationSum4(int[] nums, int target) {
 3         int size = nums.length;
 4         Arrays.sort(nums);
 5         int[] dp = new int[target + 1];
 6         dp[0] = 1;
 7         for (int i = 0; i <= target; i++) {
 8             for (int temp : nums) {
 9                 if (i + temp > target) {
10                     break;
11                 }
12                 dp[i + temp] += dp[i];
13             }
14         }
15         return dp[target];
16         
17     }
18 }
View Code

 

 ---------------我是分割線--------------------------------------

 來一枚簡單的

Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

 同樣的套路

 1 public class Solution {
 2     public List<List<Integer>> combine(int n, int k) {
 3        List<List<Integer>> res = new ArrayList<List<Integer>>();
 4        List<Integer> path = new ArrayList<Integer>();
 5        if (n < k) {
 6             return res;
 7         }
 8        helper(res, path, n, k, 1);
 9        return res;
10     }
11     private void helper (List<List<Integer>> res, List<Integer> path, int n, int k, int current) {
12         if (path.size() == k) {
13             res.add(new ArrayList<Integer>(path));
14             return;
15         }
16         for (int i = current; i <= n; i++) {
17             path.add(i);
18             helper(res, path, n, k, i + 1);
19             path.remove(path.size() - 1);
20         }
21     } 
22 }
combine

 ---------------我是分割線--------------------------------------

 Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

 可以用left,right 分別表示左括號和右括號的個數。 我的解法用了valid的int value, 當左括號時+1,右括號時-1. 確保valid大於0

這個for循環也可以不要,直接用做2次,一次left,一次right來代替

 1 public class Solution {
 2     public List<String> generateParenthesis(int n) {
 3         StringBuilder sb = new StringBuilder();
 4         List<String> res = new ArrayList<String>();
 5         int valid = 0;
 6         char[] chars = {'(',')'};
 7         helper (sb, res, valid, chars, n);
 8         return res;
 9     }
10     private static void helper(StringBuilder sb, List<String> res, int valid, char[] chars, int n) {
11         if (valid < 0) {
12             return;
13         }
14         if (sb.length() == 2*n ) {
15             if(valid == 0) {
16                 res.add(sb.toString());
17             }
18             return;
19         }
20         for (char temp : chars) {
21             sb.append(temp);
22             int tempVal = temp == '(' ?  1 :  - 1;
23             valid += tempVal;
24             helper (sb, res, valid, chars, n);
25             valid -= tempVal;
26             sb.deleteCharAt(sb.length() - 1);
27         }
28     }
29 }
Generate Parentheses

附上九章的答案,就是這么簡潔= = 

 1 public class Solution {
 2     public ArrayList<String> generateParenthesis(int n) {
 3         ArrayList<String> result = new ArrayList<String>();
 4         if (n <= 0) {
 5             return result;
 6         }
 7         helper(result, "", n, n);
 8         return result;
 9     }
10     
11     public void helper(ArrayList<String> result,
12                        String paren, // current paren
13                        int left,     // how many left paren we need to add
14                        int right) {  // how many right paren we need to add
15         if (left == 0 && right == 0) {
16             result.add(paren);
17             return;
18         }
19 
20         if (left > 0) {
21             helper(result, paren + "(", left - 1, right);
22         }
23         
24         if (right > 0 && left < right) {
25             helper(result, paren + ")", left, right - 1);
26         }
27     }
28 }
generateParenthesis

模仿九章的版本

 1 public class Solution {
 2     /**
 3      * @param n n pairs
 4      * @return All combinations of well-formed parentheses
 5      */
 6     public ArrayList<String> generateParenthesis(int n) {
 7         // Write your code here
 8         ArrayList<String> res = new ArrayList<String>();
 9         StringBuilder sb = new StringBuilder();
10         int left = 0, right = 0;
11         helper (res, sb , n, left, right);
12         return res;
13     }
14     private static void helper(List<String> res, StringBuilder sb, int n, int left, int right) {
15         if (sb.length() == 2 * n) {
16             if (left == right) {
17                 res.add(sb.toString());
18             }
19             return;
20         }
21         if (left >= right) {
22             sb.append('(');
23             helper(res, sb, n, left + 1, right);
24             sb.deleteCharAt(sb.length() - 1);
25         }
26         if (left > right) {
27             sb.append(')');
28             helper(res, sb, n, left, right + 1);
29             sb.deleteCharAt(sb.length() - 1);
30 
31         }
32     }
33 }
View Code

 

 

 

 ---------------我是分割線--------------------------------------

 Letter Combinations of a Phone Number

Given a digit string, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below.

Input:Digit string "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
 1 public class Solution {
 2     public List<String> letterCombinations(String digits) {
 3         StringBuilder sb = new StringBuilder();
 4         List<String> res = new ArrayList<String>();
 5         if (digits == null || digits.length() == 0) {
 6             return res;
 7         }
 8         HashMap<Character, String> map = new HashMap<Character, String>();
 9         map.put ('2', "abc");
10         map.put ('3', "def");
11         map.put ('4', "ghi");
12         map.put ('5', "jkl");
13         map.put ('6', "mno");
14         map.put ('7', "pqrs");
15         map.put ('8', "tuv");
16         map.put ('9', "wxyz");
17         helper (digits, map, sb, res, 0);
18         return res;
19     }
20     private static void helper (String digits, HashMap<Character, String> map, StringBuilder sb, List<String> res, int current) {
21         if (sb.length() == digits.length()) {
22             res.add(sb.toString());
23             return;
24         }
25         String temp = map.get(digits.charAt(current));
26         for (int i = 0; i < temp.length(); i++) {
27             sb.append(temp.charAt(i));
28             helper (digits, map, sb, res, current + 1);
29             sb.deleteCharAt(sb.length() - 1);
30         }
31     }
32 }
letterCombinations

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM