[leetcode] backtracking

来源:互联网 发布:网络外卖卖爆了的菜品 编辑:程序博客网 时间:2024/06/05 15:32

</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);    }


putting elements along the way:

    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;       }


0 0
原创粉丝点击