zoukankan      html  css  js  c++  java
  • 回溯法(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
     
  • 相关阅读:
    001-分布式理论-CAP定理
    006-优化web请求二-应用缓存、异步调用【Future、ListenableFuture、CompletableFuture】、ETag、WebSocket【SockJS、Stomp】
    003-RFC关于媒体类型说明
    005-优化web请求一-gzip压缩、http缓存控制和缓存校验[Pragma、Expires、Cache-Control、max-age、Last-Modified、用户刷新访问、避免过度304]
    004-restful应用构建、分布式会话、测试工具简介
    003-JSR303校验
    【Java】Callable,Runnable比较及用法
    Ubuntu下迁移MySQL数据库文件目录
    解决linux分区提示doesn't contain a valid partition table
    腾讯云Ubuntu挂载硬盘空间
  • 原文地址:https://www.cnblogs.com/jiangchen/p/5931754.html
Copyright © 2011-2022 走看看