</pre>79 Word Search (复杂度 exponential) :<p></p><p>经典dfs & backtracking:在board的每个位置做dfs search, dfs用boolean[][] 做backtracking:base case:如果对了就return true; invalid || not match就return false</p><p></p><pre name="code" class="java"> public boolean exist(char[][] board, String word) {
if (board==null||board.length==0||board[0].length==0) return false;
if (word==null||word.length()==0) return true;
boolean[][] used = new boolean[board.length][board[0].length];
for (int i=0;i<board.length;i++) {
for (int j=0;j<board[0].length;j++) {
if (search(board,word,0,i,j,used)) return true;
}
}
return false;
}
private boolean search(char[][] board, String word, int pos, int i, int j, boolean[][] used) {
if (pos==word.length()) return true;
if (i<0 || i>=board.length || j<0 || j>=board[0].length || used[i][j] || board[i][j]!=word.charAt(pos)) return false;
used[i][j]=true;
boolean found = search(board, word, pos+1, i+1, j, used) ||
search(board, word, pos+1, i, j+1, used) ||
search(board, word, pos+1, i-1, j, used) ||
search(board, word, pos+1, i, j-1, used);
if (found) return true;
used[i][j]=false;
return false;
}
78 Subsets (复杂度2^n)
backtracking:
public List<List<Integer>> subsets(int[] S) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (S==null || S.length==0) return res;
Arrays.sort(S);
helper(S, 0, res, new ArrayList<Integer>());
return res;
}
private void helper(int[] S, int pos, List<List<Integer>> res, List<Integer> item) {
if (pos==S.length) {
res.add(new ArrayList<Integer>(item));
return;
}
item.add(S[pos]);
helper(S, pos+1, res, item);
item.remove(item.size()-1);
helper(S, pos+1, res, item);
}
public List<List<Integer>> subsets(int[] S) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
res.add(new ArrayList<Integer>());
if (S==null || S.length==0) return res;
Arrays.sort(S);
for (int i=0; i<S.length;i++) helper(S, i, res);
return res;
}
private void helper(int[] S, int pos, List<List<Integer>> res) {
if (pos==S.length) return;
List<List<Integer>> temp = new ArrayList<List<Integer>>();
for (List<Integer> item: res) {
List<Integer> newItem = new ArrayList<Integer>(item);
newItem.add(S[pos]);
temp.add(newItem);
}
res.addAll(temp);
}
90 iterative method (包含重复元素:用start来取后半部分的元素):
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] num) {
if (num==null) return null;
Arrays.sort(num);
List<List<Integer>> res = new ArrayList<List<Integer>>();
res.add(new ArrayList<Integer>());
int start = 0;
for (int i=0;i<num.length;i++) {
int size = res.size();
for (int j=start;j<size;j++) {
List<Integer> temp = new ArrayList<Integer>(res.get(j));
temp.add(num[i]);
res.add(temp);
}
if (i<num.length-1 && num[i]==num[i+1]) start = size; else start = 0;
}
return res;
}
}
93 Restore IP address (复杂度constant,所有》12的都不valid):
dfs+backtracking
base case:
1. pos=length && part == 4 加
2. pos=length || part == 4 abort
3. i-pos>0 && s.charAt(pos)=='0' (前面是0) abort
4. not valid (<0 || > 255)
private void helper(String s, int pos, int part, List<Integer> item, List<String> res) {
if (pos==s.length() && part == 4) {
res.add(convert(item));
return;
}
if (pos>=s.length() || part == 4) return;
for (int i=pos; i<=pos+2 && i<s.length(); i++) {
if (i-pos>0 && s.charAt(pos)=='0') return;
int val = Integer.valueOf(s.substring(pos, i+1));
if (val>=0 && val<=255) {
item.add(val);
helper(s,i+1, part+1, item, res);
item.remove(item.size()-1);
}
}
}
private String convert(List<Integer> item) {
StringBuilder res = new StringBuilder();
for (Integer part: item) {
res.append(String.valueOf(part));
res.append('.');
}
res.deleteCharAt(res.length()-1);
return res.toString();
}
Permutation
方法一(通用的backtracking):对每一个position取每一个没有用过的element,用boolean[] used标记以用过的element
public List<List<Integer>> permute(int[] num) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (num==null||num.length==0) return res;
boolean[] used = new boolean[num.length];
helper(num, 0, used, new ArrayList<Integer>(), res);
return res;
}
private void helper(int[] num,int pos, boolean[] used, List<Integer> item,List<List<Integer>> res) {
if (pos==num.length) {
res.add(new ArrayList<Integer>(item));
return;
}
for (int i=0;i<num.length;i++) {
if (!used[i]) {
used[i]=true;
item.add(num[i]);
helper(num, pos+1,used,item,res);
item.remove(item.size()-1);
used[i]=false;
}
}
}
方法二:swap element with every element after it
Permutation ii (with duplicates)
sort, 重复的element中只对第一个未被使用的element进行recursive call
<span style="white-space:pre"> </span>for (int i=0;i<num.length;i++) {
if (i>0 && num[i]==num[i-1] && !used[i-1]) continue;
if (!used[i]) {
used[i]=true;
item.add(num[i]);
helper(num, pos+1, used,item,res);
item.remove(item.size()-1);
used[i]=false;
}
}
Combinations (exponential)
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (n<0 || k<0 || n<k ) return res;
helper(n, k, 1, 1, new ArrayList<Integer>(), res);
return res;
}
private void helper(int n, int k, int pos, int start, List<Integer> item,List<List<Integer>> res) {
if (pos>k) {
res.add(new ArrayList<Integer>(item));
return;
}
if (start>n) return;
for (int i=start; i<=n; i++) {
item.add(i);
helper(n, k, pos+1, i+1, item, res);
item.remove(item.size()-1);
}
}
Combination Sum
先sort, 再dfs backtrack
*可以使用duplicate,所以recursive call时是i
*都是positive numbers,所以target<0时就退出了(不然就infinite call了)
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (candidates==null) return res;
Arrays.sort(candidates);
helper(candidates, 0, new ArrayList<Integer>(), target, res);
return res;
}
private void helper(int[] candidates, int start, List<Integer> item, int target, List<List<Integer>> res) {
if (target==0) {
res.add(new ArrayList<Integer>(item));
return;
}
if (start>=candidates.length || target <0 ) return;
for (int i=start;i<candidates.length;i++) {
item.add(candidates[i]);
helper(candidates,i,item,target-candidates[i],res);
item.remove(item.size()-1);
}
}
Combination Sum II
duplicates的处理: sort, 直接skip非第一个的重复element
for (int i=start; i<num.length;i++) {
if (i>start && num[i]==num[i-1]) continue;
item.add(num[i]);
helper(num, target-num[i], item, res, i+1);
item.remove(item.size()-1);
}
Letter Combinations of a Phone Number
常见的recursive里做loop
*integer.valueof里如果放char会return ascii的值,所以要放string
private void helper(String digits, int start, StringBuilder item, List<String> res) {
if (start==digits.length()) {
res.add(item.toString());
return;
}
String letters = getLetters(digits.charAt(start)-'0');
for (int i=0;i<letters.length();i++) {
item.append(letters.charAt(i));
helper(digits, start+1, item, res);
item.deleteCharAt(item.length()-1);
}
}
private String getLetters(int num) {
String[] lookup = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
return lookup[num-2];
}
关于backtracking里有duplicates的处理方法:
1. subsets: 只对后半部分的res进行添加(iterative method: int start)
2. permutations: 跳过不是第一个的未使用的重复element (!used[i-1])
3. combination sum ii (candidates里可能有dup,不能重复用自己): 直接跳过后面不是第一个的重复element (因为第一个call的时候用的是i+1,所以包含了后面需要加的)
Generate Parentheses
*catalan number 复杂度o(结果数量)
public List<String> generateParenthesis(int n) {
if (n<=0) return null;
List<String> res = new ArrayList<String>();
helper(n,n,new StringBuilder(), res);
return res;
}
private void helper(int left, int right, StringBuilder item, List<String> res) {
if (left<0 || right<0 || right<left) return;
if (left==0 && right==0) {
res.add(item.toString());
return;
}
item.append('(');
helper(left-1,right,item,res);
item.deleteCharAt(item.length()-1);
item.append(')');
helper(left, right-1, item,res);
item.deleteCharAt(item.length()-1);
}
Palindrome Partitioning (return all sets of palindrome partitioning with a string)
private void helper(String s, int start, List<String> item, List<List<String>> res) {
if (start>s.length()) return;
if (start==s.length()) {
res.add(new ArrayList<String>(item));
return;
}
for (int i=start;i<s.length();i++) {
if (isP(s.substring(start,i+1))) {
item.add(s.substring(start,i+1));
helper(s, i+1, item, res);
item.remove(item.size()-1);
}
}
}
private boolean isP(String s) {
int l=0;
int r=s.length()-1;
while (l<r) {
if (s.charAt(l)!=s.charAt(r)) return false;
l++;
r--;
}
return true;
}
经典backtracking题目:
n-queens: (o(n!))
用一个colForRow[] 来represent 一张board, 从0到n-1按row来放,可以不用check row
public List<String[]> solveNQueens(int n) {
if (n<0) return null;
List<String[]> res = new ArrayList<String[]>();
if (n==0) return res;
int[] colForRow = new int[n];
helper(0, colForRow, res, n);
return res;
}
private void helper(int row, int[] colForRow, List<String[]> res, int n) {
if (row==n) {
res.add(convert(colForRow));
return;
}
for (int i=0;i<n;i++) {
colForRow[row]=i;
if (valid(colForRow, row)) helper(row+1, colForRow, res, n);
}
}
private boolean valid(int[] colForRow, int row) {
for (int i=0; i<row;i++) {
if (colForRow[i]==colForRow[row]
|| Math.abs(colForRow[row]-colForRow[i])==row-i) return false;
}
return true;
}
private String[] convert(int[] colForRow) {
String[] res = new String[colForRow.length];
StringBuilder sb = new StringBuilder();
for (int i=0;i<colForRow.length;i++) {
for (int j=0; j<colForRow.length; j++) {
if (j==colForRow[i]) sb.append('Q');
else sb.append('.');
}
res[i]=sb.toString();
sb=new StringBuilder();
}
return res;
}
sudoku solver:
public void solveSudoku(char[][] board) {
if (board==null||board.length!=9||board[0].length!=9) return;
helper(board, 0, 0);
}
private boolean helper(char[][] board, int i, int j) {
if (j>=9) return helper(board, i+1, 0);
if (i==9) return true;
if (board[i][j]!='.') return helper(board,i, j+1);
for (char c='1';c<='9';c++) {
board[i][j]=c;
if (valid(board, i, j)) {
if (helper(board, i,j+1)) return true;
}
}
board[i][j]='.';
return false;
}
private boolean valid(char[][] board, int i, int j) {
for (int k=0;k<9;k++) {
if (k!=i && board[i][j]==board[k][j]) return false;
if (k!=j && board[i][j]==board[i][k]) return false;
}
for(int row = i/3*3; row<i/3*3+3; row++)
{
for(int col=j/3*3; col<j/3*3+3; col++)
{
if((row!=i || col!=j) && board[row][col]==board[i][j])
return false;
}
}
return true;
}