回溯法(backtracking) 题目整理--------part2

Posted 毛线刷题笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回溯法(backtracking) 题目整理--------part2相关的知识,希望对你有一定的参考价值。

N-Queens

模拟退火不会写 0.0

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens\' placement, where \'Q\' and \'.\' both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

回溯法,刚开始思路,做一个2层的循环,后来发现其实每行之需要记录一个值,也就是queen的位置就行了。

先生成result strings(只包含queen位置的string), 然后把strings写成n-queue形式。

对于是否valid,写一个isvalid function. 做2个判断,1 同列是否冲突, 2 对角线是否冲突

代码:

 1 public class Solution {
 2     public List<List<String>> solveNQueens(int n) {
 3         List<List<String>> res = new ArrayList<List<String>>();
 4         if (n <= 0) {
 5             return res;
 6         }
 7         List<String> path = new ArrayList<String>();
 8         int[] row = new int[n];
 9         helper (res, row,  n, 0);
10         return res;
11     }
12      private void helper(List<List<String>> resultList,
13                               int[] row,
14                               int n,
15                               int index) {
16         if (n == index) {
17             ArrayList<String> singleResult = translateString(row);
18             resultList.add(singleResult);
19             return;
20         }
21        
22         for (int i = 0; i < n; i++) {
23                 if (isValid(row, index, i)) {
24                 row[index] = i;
25                 helper (resultList, row, n, index + 1);
26                 row[index] = 0;
27             }
28         }
29         
30     }
31     
32     private ArrayList<String> translateString(int[] row) {
33         ArrayList<String> resultList = new ArrayList<>();
34         for (int i = 0; i < row.length; i++) {
35             StringBuilder sb = new StringBuilder();
36             for (int j = 0; j < row.length; j++) {
37                 if (j == row[i]) {
38                     sb.append(\'Q\');
39                 }
40                 else {
41                     sb.append(\'.\');
42                 }
43             }
44             resultList.add(sb.toString());
45         }
46         return resultList;
47     }
48     
49     private boolean isValid(int[] row, int rowNum, int columnNum) {
50         for (int i = 0; i < rowNum; i++) {
51             if (row[i] == columnNum) {
52                 return false;
53             }
54             //对角线检查
55             if (Math.abs(row[i] - columnNum) == Math.abs(i - rowNum)) {
56                 return false;
57             }
58         }
59         return true;
60     }
61 }
n-queens

 

--------------------------我是分割线-------------------

N-Queens II

Follow up for N-Queens problem.

Now, instead outputting board configurations, return the total number of distinct solutions.

 

 注意建立的res 是静态变量,在主方法里面赋值,防止它是dirty的

 1 public class Solution {
 2     static int res;
 3     public int totalNQueens(int n) {
 4         if (n <= 0) {
 5             return 0;
 6         }
 7         int[] rows = new int[n];
 8         int index = 0;
 9         res = 0;
10         helper(0, rows);
11         return res;
12         
13     }
14     
15     private static void helper(int index,  int[] rows) {
16         int n = rows.length;
17         if (index == n) {
18             res++;
19             return;
20         }
21         for (int i = 0; i < n; i++) {
22             if (isValid(rows, index, i)) {
23                 rows[index] = i;
24                 helper(index + 1,  rows);
25             }
26         }
27     }
28     
29     private static boolean isValid(int rows[], int rowNum, int columnNum) {
30         for (int i = 0; i < rowNum; i++) {
31                 if (rows[i] == columnNum) {
32                     return false;
33                 }
34                 if (Math.abs(rows[i] - columnNum) == Math.abs(i - rowNum)) {
35                     //columnNum1 - columnNum2 = rowNum1 - rowNum2 平行!
36                     return false;
37                 }
38             }
39         return true;
40     }
41 }
totalNQueens

 

--------------------------我是分割线-------------------

Restore IP Addresses

 

Given a string containing only digits, restore it by returning all possible valid IP address combinations.

Example

Given "25525511135", return

[
  "255.255.11.135",
  "255.255.111.35"
]

Order does not matter.

写代码时候的坑:

  1. 在计算path的时候,应该用list来记录路径,确定找到结果后再转化为相应的形式。用了stringbuilder 果然是sb,使得递归主体函数变复杂了。
  2. 在每一个ip数字段的后面添加上一个. 再把最后的一个点删掉就行了。
  3. for(int i = start; i < s.length() && i < start+3; i++)  这样控制for循环就好了 i < start+3, 不需要使用2重for循环。 蠢哭了

  4. if(isvalid(tmp)) 验证是否合法比较麻烦的情况下,新建个函数放在外面

  5. if(s.charAt(0) == \'0\')
    return s.equals("0"); // to eliminate cases like "00", "01"

代码:

 1 public class Solution {
 2     /**
 3      * @param s the IP string
 4      * @return All possible valid IP addresses
 5      */
 6  
 7     
 8     public ArrayList<String> restoreIpAddresses(String s) {
 9         ArrayList<String> result = new ArrayList<String>();
10         //use list to store path data is way better that use stringBuilder
11         // not a good way StringBuilder sb = new StringBuilder();
12         ArrayList<String> list = new ArrayList<String>();
13         
14         if(s.length() < 4 || s.length() > 12)
15             return result;
16         
17         helper(result, list, s , 0);
18         return result;
19     }
20     
21     
22     
23     public void helper(ArrayList<String> result, ArrayList<String> list, String s, int start){
24         if(list.size() == 4){
25             if(start != s.length())
26                 return;
27             
28             StringBuffer sb = new StringBuffer();
29             for(String tmp: list){
30                 sb.append(tmp);
31                 sb.append(".");
32             }
33             sb.deleteCharAt(sb.length()-1);
34             result.add(sb.toString());
35             return;
36         }
37         
38         for(int i = start; i < s.length() && i < start+3; i++){
39             String tmp = s.substring(start, i+1);
40             if(isvalid(tmp)){
41                 list.add(tmp);
42                 helper(result, list, s, i+1);
43                 list.remove(list.size()-1);
44             }
45         }
46     }
47      private boolean isvalid(String s){
48         if(s.charAt(0) == \'0\')
49             return s.equals("0"); // to eliminate cases like "00", "01"
50         int digit = Integer.valueOf(s);
51         return digit >= 0 && digit <= 255;
52     }
53    
54 }
restoreIpAddresses

--------------------------我是分割线-------------------

 

Wildcard Matching

Implement wildcard pattern matching with support for\'?\' and \'*\'.

  • \'?\' Matches any single character.
  • \'*\' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

Example

isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false

 

 

没做优化,超时了

public class Solution {
    /**
     * @param s: A string 
     * @param p: A string includes "?" and "*"
     * @return: A boolean
     */
    private static boolean res;
    public boolean isMatch(String s, String p) {
        // write your code here
        res = false;
        
        helper( s, p, 0, 0);
        return res;
     }
    private static void helper(String s, String p, int sIndex , int pIndex) {
        if (sIndex == s.length() && pIndex == p.length()) {
            res = true;
            return;
        }
        if (res || (sIndex >= s.length() && p.charAt(pIndex) !=\'*\') || pIndex >= p.length() ) {
            return;
        }
        
        //test current char at p
        if (p.charAt(pIndex) == \'?\') {
            helper(s, p, sIndex + 1, pIndex + 1);
        } else if (p.charAt(pIndex) == \'*\') {
            int temp = 0;
            while (sIndex + temp <= s.length()) {
                helper(s, p, sIndex + temp, pIndex + 1);
                temp++;
            }
        } else if (p.charAt(pIndex) == s.charAt(sIndex)) {
            helper(s, p, sIndex + 1, pIndex + 1);
        } else {
            return;
        }
        
    }
}
isMatch

优化:

// without this optimization, it will fail for large data set
int plenNoStar = 0;
for (char c : p.toCharArray())
if (c != \'*\') plenNoStar++;
if (plenNoStar > s.length()) return false;

 

尼玛 加了优化还是挂了

答案= = 动态规划

public class Solution {

public boolean isMatch(String s, String p) {
    // without this optimization, it will fail for large data set
    int plenNoStar = 0;
    for (char c : p.toCharArray())
        if (c != \'*\') plenNoStar++;
    if (plenNoStar > s.length()) return false;

    s = " " + s;
    p = " " + p;
    int slen = s.length();
    int plen = p.length();

    boolean[] dp = new boolean[slen];
    TreeSet<Integer> firstTrueSet = new TreeSet<Integer>();
    firstTrueSet.add(0);
    dp[0] = true;

    boolean allStar = true;
    for (int pi = 1; pi < plen; pi++) {
        if (p.charAt(pi) != \'*\')
            allStar = false;
        for (int si = slen - 1; si >= 0; si--) {
            if (si == 0) {
                dp[si] = allStar ? true : false;
            } else if (p.charAt(pi) != \'*\') {
                if (s.charAt(si) == p.charAt(pi) || p.charAt(pi) == \'?\') dp[si] = dp[si-1];
                else dp[si] = false;
            } else {
                int firstTruePos = firstTrueSet.isEmpty() ? Integer.MAX_VALUE : firstTrueSet.first();
                if (si >= firstTruePos) dp[si] = true;
                else dp[si] = false;
            }
            if (dp[si]) firstTrueSet.add(si);
            else firstTrueSet.remove(si);
        }
    }
    return dp[slen - 1];
}
}
View Code

-------分割线---- 

Word Search

public class Solution {
    private int[] offset;
    private boolean[][] flag;
    private int m, n;
    
    public boolean exist(char[][] board, String word) {
        m = board.length;
        n = board[0].length;
        flag = new boolean[m][n];
        offset = new int[]{0, 1, 0, -1, 0};
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                flag[i][j] = true;
                if (word.charAt(0) == board[i][j]) {
                   // System.out.println("searching pos i == " + i + " j== " + j);
                    if (search(board, word, 1, i, j)){
                        return true;
                    }
                }
                flag[i][j] = false;
            }
        }
        return false;
    }
    private boolean search (char[][] board, String word, int pos, int i, int j) {
        if (pos == word.length()) {
            return true;
        }
        
        for (int k = 0; k < 4; k++) {
            //判断是否越界
            int new_i = i + offset[k], new_j = j + offset[k + 1];
            if (new_i < 0 || new_j < 0 || new_i >= m || new_j >= n) {
                continue;
            }
            //没越界,并且没有往来的方向返回的话,进行下一层的搜索
            if (word.charAt(pos) == board[new_i][new_j] && flag[new_i][new_j] == false) {
                flag[new_i][new_j] = true;
                 if (search(board, word, pos + 1, new_i, new_j)) {
                     return true;
                 }
                flag[new_i][new_j] = false;

            }
        }
        return false;
    }
}
word search

 

 

 

以上是关于回溯法(backtracking) 题目整理--------part2的主要内容,如果未能解决你的问题,请参考以下文章

[Leetcode] Backtracking回溯法解题思路

LeetCode回溯法 backtracking(共39题)

LeetCode回溯法 backtracking(共39题)

LeetCode回溯系列——第17题解法

回溯法

算法知识目录整理