zoukankan      html  css  js  c++  java
  • 算法 *-* 回溯算法 (类似枚举的搜索过程,通解通法美称)

    什么是回溯算法

    对于回溯算法的定义,百度百科上是这样描述的:回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称

    看明白没,回溯算法其实就是一个不断探索尝试的过程,探索成功了也就成功了,探索失败了就在退一步,继续尝试……,

    必看解析

    1-什么叫回溯算法,一看就会,一写就废

    2-回溯算法详解(修订版)

    回溯算法的框架:

    result = []
    def backtrack(路径, 选择列表):
        if 满足结束条件:
            result.add(路径)
            return
    
        for 选择 in 选择列表:
            做选择
            backtrack(路径, 选择列表)
            撤销选择
    

    不同数据结构的 “撤销刚刚的选择” 

    1.ArrayList (所有实现List接口的实现类)

    ArrayList<Integer> track

    track.remove(track.size()-1);

    2.StringBuilder

    StringBuilder builder

    builder.deleteCharAt(cur.length() - 1);

    必看例子

    Attention: 注意“全排列”和“所有子集”中backtrack()的参数区别。

    • “所有子集”中有一个start参数,代表遍历到了哪里,不走回头路,是为了防止重复
    • “全排列”本身就是各种元素的排序,元素肯定是重复的,所有就没有这个start参数,索引始终从0开始。

    全排列

    LeetCode 46 - 全排列  

    class Solution {
        public List<List<Integer>> permute(int[] nums) {
            //暂存结果
            ArrayList<Integer> track = new ArrayList<>();
            //最终结果
            List<List<Integer>> result = new ArrayList<>();
            //回溯函数
            backtrack(nums, track, result);
            return result;
        }
    
        private void backtrack(int[] nums, ArrayList<Integer> track, List<List<Integer>> result){
            //end condition
            if(track.size() == nums.length){
                result.add(new ArrayList(track));
                return;
            }
    
            //【重要】每次索引都从0开始!!!这里和“所有子集”问题不同
            for(int i = 0; i < nums.length; i++){
                //用contains判断是否存在
                if(! track.contains(nums[i])){
                    track.add(nums[i]);
                    backtrack(nums, track, result);
                    //删除容器里,最后一个索引的值
                    track.remove(track.size()-1);
                }
            }
        }
    }
    

    所有子集

    Leetcode 78 - 子集

    class Solution {
        public List<List<Integer>> subsets(int[] nums) {
            List<List<Integer>> res = new ArrayList<>();
            List<Integer> track = new ArrayList<>();
    
            backtrack(nums, 0, track, res);
    
            return res;
    
        }
    
    //【重要】注意这个参数start private void backtrack(int[] nums, int start, List<Integer> track, List<List<Integer>> res){ //每一个路径,都是一个解 //【重要】这里没有明显的一个递归出口,而是靠下面的for循环的终止条件 //【重要】因为track是公用的,所以在加入res前,需要复制一份新的 res.add(new ArrayList(track));
    //每次递归不是从0开始,而是start for(int i = start; i < nums.length; i++){ //重要】i 已经放在了track暂时解中,因此在此前提下,之后的递归就要exclude这个i,那就i+1即可 track.add(nums[i]); //System.out.println("track add " + nums[i]); backtrack(nums, i+1, track, res); track.remove(track.size() - 1); } } }
  • 相关阅读:
    页面访问权限控制
    购物车效果
    content: "e600"
    wf-删除所选
    event.target.getAttribute('id')
    css content
    mysql 浏览器submit中文, shell乱码
    导入导出
    mysql 标点符号
    mysql json
  • 原文地址:https://www.cnblogs.com/frankcui/p/13833204.html
Copyright © 2011-2022 走看看