zoukankan      html  css  js  c++  java
  • 回溯法专题

    回溯法专题

      回溯法(Backtracking)指的是在每个状态的固化,比如f(1)是一个状态,f(2)是另一个状态。从f(1)到f(2),状态改变,各种依赖状态的数据也改变了,那么从f(2)到f(1)的时候,又回到了f(1)的状态了。回溯常常配合深度优先执行,在往深度时候,数据产生变化,然后在递归回来的时候,又回到了之前的状态。

    46. Permutations

       拿这道全排列来讲,它按照正常顺序列出了全部的排列结果,也可以叫做字典序,主要是输入是按从小到大的话,输出就是字典序。

       按照递归的方式来做这道题的话,那么就是for循环的起点和变量,决定了交换哪两个数。

       比如输入是1,2,3,第一次交换就是 1,3,2;在递归栈出来的时候,变成1,2,3;然后再次交换是2,1,3,再是2,3,1,最后再出来的时候就会变成1,2,3。

       主要在这段

                swap(nums,n,j);
                sortNums(nums,n+1,len);
                swap(nums,n,j);
    class Solution {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        public List<List<Integer>> permute(int[] nums) {
    
            if(nums ==null)
                return result;
            int len = nums.length;
            sortNums(nums, 0, len);
            return result;
        }
        public void sortNums(int[] nums, int n, int len){
            List<Integer> list = new ArrayList();
            if(len-1 ==n){
                for(int i =0; i <len; i++){
                    list.add(nums[i]);
    
                }
                result.add(list);
                return;
            }
            for(int j =n; j <len; j++){
                swap(nums,n,j);
                sortNums(nums,n+1,len);
                swap(nums,n,j);     
            }
        }
        public void swap(int[] nums, int n, int j){
            int temp = 0;
            temp = nums[n];
            nums[n] = nums[j];
            nums[j] = temp;
        }
    }

    47. Permutations II

       在这道题中,它拥有重复元素,在排列的时候使用上一题的swap方式,那么会有两个1,1,2出来,题意是过滤掉这个重复值,可以使用set过滤。

    class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) {
            List<List<Integer>> result = new ArrayList<List<Integer>>();
            if(nums == null){
                return  result;
            }else if(nums.length < 2){
                List<Integer> rList = new ArrayList<Integer>();
                for(int v : nums){
                    rList.add(v);
                }
                result.add(rList);
                return result;
            }
            Set<Long> filter = new HashSet<Long>();
            perm(nums,0,nums.length-1,result,filter);
    
            return result;
    
        }
    
        void perm(int[] nums,int k,int m,List<List<Integer>> result,Set<Long> filter){
            if(k == m){
                List<Integer> rList = new ArrayList<Integer>();
                long tag = 0;
                for(int v :nums){
                    tag = tag * 10 + v;
                    rList.add(v);
                }
                if(!filter.contains(tag)){
                    result.add(rList);
                    filter.add(tag);
                }
    
            }else {
                for(int i=k;i<=m;i++){
                    if(i != k && nums[i] == nums[k])
                        continue;
                    swap(nums,i,k);
                    perm(nums,k+1,m,result,filter);
                    swap(nums,i,k);
                }
            }
        }
    
        boolean swap(int[] nums,int i,int j){
            if(i == j)
               return false;
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            return true;
        }
    
    }

    79. Word Search

       这个题目乍一看懵逼,仔细看就知道了,一个迷宫,如果能吃掉你输入的序列,那么就是true,这是回溯的经典题目。

       关键点是朝着四个方向尝试,并且使用数组visited标记是否已经访问过,记得再出栈的时候将visited还原。

    public class WordSearch {
        public void test(){
            char[][] board ={
                    {'A','B','C','E'},
                    {'S','F','C','S'},
                    {'A','D','E','E'}
            };
            // true
            System.out.println(exist(board,"ABCCED"));
            // true
            System.out.println(exist(board,"SEE"));
            // false
            System.out.println(exist(board,"ABCB"));
    
            char[][] board1={
                    {'A','B','C','E'},
                    {'S','F','E','S'},
                    {'A','D','E','E'}};
            // true
            System.out.println(exist(board1, "ABCESEEEFS"));
    
        }
    
    
        public boolean exist(char[][] board, String word) {
            boolean[][] visited = new boolean[board.length][board[0].length];
            for(int i=0;i<board.length;i++){
                for(int j=0;j<board[i].length;j++){
                    if(dps(board,i,j,0,word,visited)){
                        return true;
                    }
                }
            }
            return false;
        }
        boolean dps(char[][] board,int i,int j,int index,String word,boolean[][] visited){
            if(index >= word.length()){
                return true;
            }
            if(i<0 || i>=board.length){
                return false;
            }
            if(j<0 || j>=board[0].length){
                return false;
            }
            if(visited[i][j]){
                return false;
            }
            if(board[i][j] == word.charAt(index)){
                visited[i][j]=true;
                boolean exist = dps(board,i-1,j,index+1,word,visited) || dps(board,i+1,j,index+1,word,visited)
                        || dps(board,i,j+1,index+1,word,visited) || dps(board,i,j-1,index+1,word,visited);
                visited[i][j]=false;
                return exist;
            }else {
                return false;
            }
        }
    }

    78. Subsets

       集合子集分割,高中数学第一章。

    class Solution {
        public List<List<Integer>> subsets(int[] nums) {
            List<List<Integer>> result = new ArrayList<>();
            if(nums == null || nums.length == 0){
                return result;
            }
            recursion(nums,0,new ArrayList<>(),result);
            return result;
        }
        void recursion(int[] nums,int i,List<Integer> each,List<List<Integer>> result){
            if(i>=nums.length){
                result.add(new ArrayList<>(each));
            }else {
                each.add(nums[i]);
                recursion(nums,i+1,each,result);
                each.remove(each.size()-1);
                recursion(nums,i+1,each,result);
            }
        }
    }

    90. Subsets II

       重复元素的子集分割。

    class Solution {
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            List<List<Integer>> result = new ArrayList<>();
            if(nums == null || nums.length == 0){
                return result;
            }
            Arrays.sort(nums);
            Set<List<Integer>> filter = new HashSet<>();
            recursion(nums,0,new ArrayList<>(),filter);
            result.addAll(filter);
            return result;
        }
        void recursion(int[] nums, int i, List<Integer> each, Set<List<Integer>> result){
            if(i >= nums.length){
                result.add(new ArrayList<>(each));
            }else {
                each.add(nums[i]);
                recursion(nums,i+1,each,result);
                each.remove(each.size()-1);
    
                recursion(nums,i+1,each,result);
            }
        }
    }
  • 相关阅读:
    Clion 配置
    JetBrains 全套激活 Pycharm Clion 高校学生老师免费用
    VS Code 搭建 C/C++ 编译运行环境的四种方案 (待完善)
    专治编译器编辑器vscode中文乱码输出 win10 配置系统默认utf-8编码
    AlexeyAB大神版yolo 待完善
    Python 的 GUI 开发工具
    Python打包—Pyinstaller
    pip freeze 打包依赖库及setup.py
    jenkins中布置python测试
    在Ubuntu上安装Jenkins
  • 原文地址:https://www.cnblogs.com/chentingk/p/11697506.html
Copyright © 2011-2022 走看看