[Algorithm]九章五.DFS

来源:互联网 发布:朕是什么意思网络此意 编辑:程序博客网 时间:2024/06/05 00:43

17. Subsets:  点击打开链接

思路:对于[1,2,3]
             [ ]
         [1]  这边的1是在[ ]的基础上添加的
    [1,2]    [1,3]  所以倒回来到[1,3]的时候也应该知道是在[1]的基础上添加的
[1,2,3]  因为这层是在[1,2]的基础上添加的3
public class Solution {    public List<List<Integer>> subsets(int[] nums) {        List<List<Integer>> result=new ArrayList<>();        if(nums==null || nums.length==0){            return result;        }        Arrays.sort(nums);        helper(result,new ArrayList<>(),nums,0);        return result;    }        private void helper(List<List<Integer>> result,List<Integer> list,int[] nums,int start){              result.add(new ArrayList<>(list));                for(int i=start;i<nums.length;i++){            list.add(nums[i]);            helper(result,list,nums,i+1);            list.remove(list.size()-1);        }    }}

18. Sebsets II: 点击打开链接

class Solution {    /**     * @param nums: A set of numbers.     * @return: A list of lists. All valid subsets.     */    public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] nums) {       ArrayList<ArrayList<Integer>> results=new ArrayList<>();       ArrayList<Integer> list=new ArrayList<>();              Arrays.sort(nums);              if(nums==null){           return results;       }       if(nums.length==0){           results.add(list);           return results;       }              helper(nums,0,results,list);              return results;    }        private void helper(int[] nums, int startIndex,ArrayList<ArrayList<Integer>> results,ArrayList<Integer> list){        results.add(new ArrayList<>(list));                for(int i=startIndex;i<nums.length;i++){              //此处if语句也说明了之前数组排序的重要性            if(i!=0 && nums[i]==nums[i-1] && i>startIndex){   //首先要防止数组角标越界:i!=0                continue;                                     //比较前后两个数是针对后面再一次出现同一个数的情况            }                                                 //如果前一个同样的数还没有放进去过,就不能放后一个同样的数;            list.add(nums[i]);                                            helper(nums,i+1,results,list);            list.remove(list.size()-1);        }    }}

135.Combination Sum:   点击打开链接

1.   [2]

 -> [2,2]

 -> [2,2,2]

 -> [2,2,2,2], 判断和大于target,后面的[2,2,2,3],[2,2,2,6],[2,2,2,7]都不用再判断,break。

2.  回到i++,也就是外一圈的helper,[2,2,3]里判断,此时正好等于target,return。

     判断[2,2,6],和大于target,后面的整个[2,2,7]都垮掉。

3. 再回到外一圈的helper,[2,3]里判断,以此类推。

4. 直到以[2]开头的都判断完,回到最外层helper,再判断以[3]开头的。

注意:当一个元素可以用很多次,结果又不能有重复list,就要取出原数组的重复元素

public class Solution {    public List<List<Integer>> combinationSum(int[] candidates, int target) {        List<List<Integer>> result=new ArrayList<>();        List<Integer> list=new ArrayList<>();                if(candidates==null || candidates.length==0){            return result;        }                int[] nums=removeDuplicates(candidates);        helper(nums,target,0,0,result,list);        return result;    }    //递归的定义:寻找所有以list开头的满足条件的组合,放到result里    private void helper(int[] nums,int target,int startIndex,int sum,List<List<Integer>> result,List<Integer> list){        if(sum==target){                                    //递归的出口            result.add(new ArrayList<Integer>(list));            return;        }                for(int i=startIndex;i<nums.length;i++){            //这里的for循环执行两种功能,如果可以继续加值,里层的helper用的            if(sum+nums[i]>target){                         //还有就是remove最后一个元素后,同一层的下一个组合用的                break;                                      //一旦break,跳出整体for循环,并不是本层for循环            }            list.add(nums[i]);            helper(nums,target,i,sum+nums[i],result,list);  //i的取值也很讲究:只要是元素可以重复使用,下次取的时候还是位置i            list.remove(list.size()-1);                             }    }    private int[] removeDuplicates(int[] candidates){       //去重是必要的,不然result里可能会有重复小list        Arrays.sort(candidates);        ArrayList<Integer> list=new ArrayList<>();        for(int i=0;i<candidates.length;i++){            if(!list.contains(candidates[i])){                list.add(candidates[i]);            }        }                int[] nums=new int[list.size()];        for(int i=0;i<list.size();i++){            nums[i]=list.get(i);        }        return nums;    }}

public class Solution {    public List<List<Integer>> combinationSum(int[] candidates, int target) {        List<List<Integer>> result=new ArrayList<>();        List<Integer> list=new ArrayList<>();        if(candidates==null || candidates.length==0){            return result;        }        int[] nums=removeDuplicates(candidates);        helper(nums,target,0,0,result,list);        return result;    }        private void helper(int[] nums,int target,int startIndex,int sum,List<List<Integer>> result,List<Integer> list){        if(sum==target){            result.add(new ArrayList<Integer>(list));            return;        }                for(int i=startIndex;i<nums.length;i++){            if(sum<target){                                                   list.add(nums[i]);                helper(nums,target,i,sum+nums[i],result,list);                list.remove(list.size()-1);            }        }    }        private int[] removeDuplicates(int[] nums){        Arrays.sort(nums);        int index=0;        for(int i=0;i<nums.length;i++){            if(nums[i]!=nums[index]){                index++;                nums[index]=nums[i];            }        }        int[] result=new int[index+1];        for(int i=0;i<result.length;i++){            result[i]=nums[i];        }        return result;    }}

153. Combination Sum II :   点击打开链接

注意:当一个元素只可以用一次,原数组里又有重复元素,结果又不能有重复list,就要判断后面的元素是不是先于前面的元素被使用
public class Solution {    public List<List<Integer>> combinationSum2(int[] candidates, int target) {        List<List<Integer>> result=new ArrayList<>();        List<Integer> list=new ArrayList<>();        if(candidates==null || candidates.length==0){            return result;        }        Arrays.sort(candidates);        helper(candidates,target,0,0,result,list);        return result;    }        private void helper(int[] nums,int target,int startIndex,int sum,List<List<Integer>> result,List<Integer> list){        if(sum==target){            result.add(new ArrayList<Integer>(list));            return;        }                for(int i=startIndex;i<nums.length;i++){            if(sum<target){                if(i!=0 && nums[i]==nums[i-1] && i!=startIndex){        //因为i-1等于startIndex                    continue;                                           //nums[i-1]没有被拿过,就不能拿nums[i]                }                list.add(nums[i]);                helper(nums,target,i+1,sum+nums[i],result,list);                list.remove(list.size()-1);            }        }    }  }

136. Palindrome Partitioning:  点击打开链接

public class Solution {    /**     * @param s: A string     * @return: A list of lists of string     */    public List<List<String>> partition(String s) {        List<List<String>> result=new ArrayList<>();        List<String> list=new ArrayList<>();                if(s==null || s.length()==0){            return result;        }                helper(s,0,result,list);                return result;    }        private void helper(String s,int startIndex,List<List<String>> result,List<String> list){        if(startIndex==s.length()){            result.add(new ArrayList<>(list));            return;        }                for(int i=startIndex;i<s.length();i++){            String sub=s.substring(startIndex,i+1);            if(!isPalindrome(sub)){                continue;                                    //并不是最大层for循环整体垮掉,只是终止本层for循环            }            list.add(sub);            helper(s,i+1,result,list);            list.remove(list.size()-1);        }    }        private boolean isPalindrome(String s){        for(int i=0, j=s.length()-1; i<j ; i++, j--){            if(s.charAt(i)!=s.charAt(j)){                return false;            }        }        return true;    }}

15. Permutations:  点击打开链接

public class Solution {    public List<List<Integer>> permute(int[] nums) {                            //recursion方法一        List<List<Integer>> result=new ArrayList<>();        if(nums==null || nums.length==0){            return result;        }                int[] visited=new int[nums.length];        for(int i=0;i<nums.length;i++){            visited[i]=0;        }        helper(result,new ArrayList<>(),nums,visited);        return result;            }        private void helper(List<List<Integer>> result,List<Integer> list,int[] nums,int[] visited){        if(list.size()==nums.length){            result.add(new ArrayList<>(list));            return;        }                for(int i=0;i<nums.length;i++){            if(visited[i]==1){                 continue;            }            list.add(nums[i]);            visited[i]=1;            helper(result,list,nums,visited);            list.remove(list.size()-1);            visited[i]=0;                   }    }}
class Solution {                                                                //recursion方法二    /**     * @param nums: A list of integers.     * @return: A list of permutations.     */    public List<List<Integer>> permute(int[] nums) {        List<List<Integer>> result=new ArrayList<>();        List<Integer> list=new ArrayList<>();                if(nums==null){            return result;        }                if(nums.length==0){            result.add(list);            return result;        }                helper(result,list,nums);        return result;    }             private void helper(List<List<Integer>> result,                        List<Integer> list,                        int[] nums){        if(list.size()==nums.length){            result.add(new ArrayList<>(list));            return;        }                for(int i=0;i<nums.length;i++){            if(list.contains(nums[i])){                continue;            }                        list.add(nums[i]);            helper(result,list,nums);            list.remove(list.size()-1);        }    }}

16. Permuations II :  点击打开链接

class Solution {    /**     * @param nums: A list of integers.     * @return: A list of permutations.     */        public List<List<Integer>> permuteUnique(int[] nums) {        List<List<Integer>> result=new ArrayList<>();        List<Integer> list=new ArrayList<>();                if(nums==null){            return result;        }                if(nums.length==0){            result.add(list);            return result;        }                Arrays.sort(nums);                int[] visited=new int[nums.length];        for(int i=0;i<visited.length;i++){            visited[i]=0;        }                helper(result,list,nums,visited);        return result;    }        private void helper(List<List<Integer>> result,                        List<Integer> list,                        int[] nums,                        int[] visited){        if(list.size()==nums.length){            result.add(new ArrayList<>(list));            return;        }                for(int i=0;i<nums.length;i++){            if(visited[i]==1 || (i!=0 && nums[i]==nums[i-1] && visited[i-1]==0)){                  continue;    //如果有相同元素的情况下,如果前面的元素还没有使用的时候,就不能让后面这个元素使用            }                //也就是轮到这个元素的时候,它已经被放进去了,或者它前面的元素还没有被放进去                        list.add(nums[i]);            visited[i]=1;            helper(result,list,nums,visited);            list.remove(list.size()-1);            visited[i]=0;        }    }}

33. N-Queens:  点击打开链接

1.同的一行不能存在两个皇后,但是又正好是N个皇后又要放在N行上,这就意味着每一行都有且仅有一个皇后,于是我们可以按照这样的方式来枚举这道题目的所有方案:依次枚举每一行皇后的位置,在这个枚举过程中确保不会在每一列、每一条斜线上出现两个皇后,对于行里面的每一个元素,都要遍历一次这个元素对应的一整列。

2.以[1,3,0,2]的ArrayList为例,也就是arrayList.get(0)=1, arrayList.get(1)=3, arrayList.get(2)=0, arrayList.get(3)=2

QQQQ

3.明确造成斜线攻击的条件:同一个斜线上的坐标之差相等,反方向上是同一个斜线上坐标之和相等。

class Solution {    /**     * Get all distinct N-Queen solutions     * @param n: The number of queens     * @return: All distinct solutions     * For example, A string '...Q' shows a queen on forth position     */    ArrayList<ArrayList<String>> solveNQueens(int n) {        ArrayList<ArrayList<String>> result=new ArrayList<>();        ArrayList<Integer> cols=new ArrayList<>();        if(n<=0){            return result;        }        search(result,cols,n);        return result;    }        private void search(ArrayList<ArrayList<String>> result,                         ArrayList<Integer> cols,                        int n){        if(cols.size()==n){            result.add(drawChessBoard(cols));            return;        }                for(int colIndex=0;colIndex<n;colIndex++){            if(!isValid(cols,colIndex)){                continue;            }            cols.add(colIndex);            search(result,cols,n);            cols.remove(cols.size()-1);        }    }        private boolean isValid (ArrayList<Integer> cols,int column){       //判断有效落子位置        int row=cols.size();        for(int rowIndex=0;rowIndex<cols.size();rowIndex++){            //行里面的每一个元素,都要遍历一次这个元素对应的一整列            if(cols.get(rowIndex)==column){                             //造成列攻击                return false;            }            if(rowIndex+cols.get(rowIndex)==row+column){                //造成斜线攻击                return false;             }            if(rowIndex-cols.get(rowIndex)==row-column){                //造成斜线攻击                return false;             }        }        return true;    }        private ArrayList<String> drawChessBoard(ArrayList<Integer> cols) { //每一个solution画成棋盘        ArrayList<String> solution = new ArrayList<>();                for (int i = 0; i < cols.size(); i++) {            StringBuilder sb = new StringBuilder();            for (int j = 0; j < cols.size(); j++) {                if(j == cols.get(i)){                    sb.append('Q');                }else{                    sb.append('.');                }            }            solution.add(sb.toString());        }        return solution;        //最后以这样的形式表示棋盘[.Q.., ...Q, Q..., ..Q.], 以[1,3,0,2]为例    }}

34.N-Queens II :  点击打开链接

N-QueensII相对于I其实是更简单了,不让打印满足条件的棋盘,而是输出满足条件的棋盘个数。

class Solution {    /**     * Calculate the total number of distinct N-Queen solutions.     * @param n: The number of queens.     * @return: The total number of distinct solutions.     */        public int sum;    public int totalNQueens(int n) {       sum=0;       search(new ArrayList<Integer>(), n);       return sum;    }        private void search(ArrayList<Integer> solution,int n){    //注意这边不用初始化sum=0;        if(solution.size()==n){            sum++;            return;        }                for(int colIndex=0; colIndex<n; colIndex++){            if(!isValid(solution,colIndex)){                continue;            }                        solution.add(colIndex);            search(solution,n);            solution.remove(solution.size()-1);        }    }        private boolean isValid(ArrayList<Integer> solution,int column){        int row=solution.size();        for(int rowIndex=0;rowIndex<solution.size();rowIndex++){            if(solution.get(rowIndex)==column){                return false;            }            if(rowIndex+solution.get(rowIndex)==row+column){                return false;            }            if(rowIndex-solution.get(rowIndex)==row-column){                return false;            }        }                return true;    }};

12.Min Stack:点击打开链接

public class MinStack {        Stack<Integer> stack=new Stack<>();    Stack<Integer> minStack=new Stack<>();        public MinStack() {        // do initialize if necessary    }    public void push(int number) {        stack.push(number);        if(minStack.isEmpty() || minStack.peek()>=number){ //如果栈是空的,可以直接放,如果栈里有就要比较与加入number的大小            minStack.push(number);                         //只有原来peek的比number的值大至少等于number,才可以加入number        }                                                  //也就是说,如果要加入的一直比minStack.peek()的大,就一直不加入minStack里    }    public int pop() {        int x=stack.pop();              if(minStack.peek()==x){                            //如果当初加入的时候加入的比minStack原有的大,则minStack不加入            minStack.pop();                                //这时pop的时候minStack也不pop        }                                                          return x;    }    public int min() {        return minStack.peek();    }}

575.Expression Expand:  点击打开链接

public class Solution {    /**     * @param s  an expression includes numbers, letters and brackets     * @return a string     */    public String expressionExpand(String s) {        Stack<Object> stack=new Stack<>();        int num=0;                for(char c : s.toCharArray()){                //c只有4种:数字, '[', ']'或者字符串            if(Character.isDigit(c)){                 //如果是数字,就拿到数字                num=num*10+c-'0';            }else if(c=='['){                         //如果是'[',就把数字入栈               stack.push(Integer.valueOf(num));      //数字入栈之后要归零,后面的数字还要在for循环里出现               num=0;                                             }else if(c==']'){                         //如果是']',就要拿出[]所包含的字符串,并让之前相应的数字出栈                String curString=popStack(stack);                     Integer count=(Integer)stack.pop();                for(int i=0;i<count;i++){             //有几个字符串,就以for循环的形式入栈几次                    stack.push(curString);            //解决了形如 3[abc]这样的问题                }            }else{                                    //如果是字符串,就直接入栈                stack.push(String.valueOf(c));            }        }        return popStack(stack);                       //最后最大括号的整体也要当做字符串    }         private String popStack(Stack<Object> stack){     //将stack里的字符串出栈,导入暂时栈temp,然后添加到sb里转化为String        Stack<String> tempStack=new Stack<>();        String str=null;        while(!stack.isEmpty() && stack.peek() instanceof String){            tempStack.push((String) stack.pop());        }                StringBuilder sb=new StringBuilder();        while(!tempStack.isEmpty()){            sb.append(tempStack.pop());        }        return sb.toString();    }}

433.Numbers of Islands: 点击打开链接

对于每一个grid[i][j]点进行遍历, 如果是小岛,即grid[i][j] == true,则result+1,并对四个方向进行DFS查找(查找的时候要先判断有效点,也就是坐标加减后还在给定矩阵中的点),并将所有属于那坐岛屿的点标记为非岛屿。这样遍历过的地方全部会变成非岛屿,而岛屿的数量已被记录。(标记的意义在于:不会对同一块已经计数过的小岛反复计数)。

public class Solution {    /**     * @param grid a boolean 2D matrix     * @return an integer     */    public int numIslands(boolean[][] grid) {                        //写法一        if(grid==null || grid.length==0){            return 0;        }                int result=0;        for(int i=0;i<grid.length;i++){            for(int j=0;j<grid[0].length;j++){                if(grid[i][j]==true){                    result++;                    dfs(grid,i,j);                }            }        }        return result;    }        private void dfs(boolean[][] grid,int x,int y){                  //找grid[i][j]四周为岛屿的点        int[] dx={0,0,-1,1};                                         //如果有就把它们标记为false,表示和grid[i][j]连接        int[] dy={-1,1,0,0};        if(isValid(grid,x,y) && grid[x][y]==true){            grid[x][y]=false;            for(int k=0;k<4;k++){                dfs(grid,x+dx[k],y+dy[k]);            }        }    }        private boolean isValid(boolean[][] grid,int x,int y){        if(x<0 || x>=grid.length){            return false;        }        if(y<0 || y>=grid[0].length){            return false;        }        return true;    }}

public class Solution {    /**     * @param grid a boolean 2D matrix     * @return an integer     */    public int numIslands(boolean[][] grid) {                          //写法二,思路是一样的        if(grid==null || grid.length==0){           return 0;         }              int result=0;        for(int i=0;i<grid.length;i++){            for(int j=0;j<grid[0].length;j++){                if(grid[i][j]==true){                   result++;                   dfs(grid,i,j);                }            }        }        return result;    }        private void dfs(boolean[][] grid, int i, int j){        if(i<0 || i>=grid.length || j<0 || j>=grid[0].length){            return;        }               if(grid[i][j]==true){            grid[i][j]=false;            dfs(grid,i+1,j);            dfs(grid,i-1,j);            dfs(grid,i,j+1);                dfs(grid,i,j-1);        }    }}

0 0
原创粉丝点击