[leetcode] backtracking

</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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值