回溯法(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 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 }
--------------------------我是分割线-------------------
Restore IP Addresses
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
Given "25525511135"
, return
[
"255.255.11.135",
"255.255.111.35"
]
Order does not matter.
写代码时候的坑:
- 在计算path的时候,应该用list来记录路径,确定找到结果后再转化为相应的形式。用了stringbuilder 果然是sb,使得递归主体函数变复杂了。
- 在每一个ip数字段的后面添加上一个. 再把最后的一个点删掉就行了。
-
for(int i = start; i < s.length() && i < start+3; i++) 这样控制for循环就好了 i < start+3, 不需要使用2重for循环。 蠢哭了
-
if(isvalid(tmp)) 验证是否合法比较麻烦的情况下,新建个函数放在外面
-
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 }
--------------------------我是分割线-------------------
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; } } }
优化:
// 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]; } }
-------分割线----
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; } }
以上是关于回溯法(backtracking) 题目整理--------part2的主要内容,如果未能解决你的问题,请参考以下文章
[Leetcode] Backtracking回溯法解题思路
LeetCode回溯法 backtracking(共39题)