• 简单易懂回溯算法


    一、什么是回溯算法

    回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。

    回溯算法实际上一个类似枚举的深度优先搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回(也就是递归返回),尝试别的路径。

    二、回溯算法思想

      回溯法一般都用在要给出多个可以实现最终条件的解的最终形式。回溯法要求对解要添加一些约束条件。总的来说,如果要解决一个回溯法的问题,通常要确定三个元素:

    1、选择。对于每个特定的解,肯定是由一步步构建而来的,而每一步怎么构建,肯定都是有限个选择,要怎么选择,这个要知道;同时,在编程时候要定下,优先或合法的每一步选择的顺序,一般是通过多个if或者for循环来排列。

    2、条件。对于每个特定的解的某一步,他必然要符合某个解要求符合的条件,如果不符合条件,就要回溯,其实回溯也就是递归调用的返回。

    3、结束。当到达一个特定结束条件时候,就认为这个一步步构建的解是符合要求的解了。把解存下来或者打印出来。对于这一步来说,有时候也可以另外写一个issolution函数来进行判断。注意,当到达第三步后,有时候还需要构建一个数据结构,把符合要求的解存起来,便于当得到所有解后,把解空间输出来。这个数据结构必须是全局的,作为参数之一传递给递归函数。

    三、递归函数的参数的选择,要遵循四个原则

    1、必须要有一个临时变量(可以就直接传递一个字面量或者常量进去)传递不完整的解,因为每一步选择后,暂时还没构成完整的解,这个时候这个选择的不完整解,也要想办法传递给递归函数。也就是,把每次递归的不同情况传递给递归调用的函数。

    2、可以有一个全局变量,用来存储完整的每个解,一般是个集合容器(也不一定要有这样一个变量,因为每次符合结束条件,不完整解就是完整解了,直接打印即可)。

    3、最重要的一点,一定要在参数设计中,可以得到结束条件。一个选择是可以传递一个量n,也许是数组的长度,也许是数量,等等。

    4、要保证递归函数返回后,状态可以恢复到递归前,以此达到真正回溯。

    四、学习例题

    1.给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

    例如,给出 = 3,生成结果为:

    [

      "((()))",

      "(()())",

      "(())()",

      "()(())",

      "()()()"

    ]

     

    2.思路

    首先利用回溯枚举出所有括号的可能性,然后进行判断是否符合要求(n对并且是有效的括号组合),就添加到list表格中。

    对于递归函数变量需要全局变量列表list:用来存储符合要求的括号组合。

                        局部变量temp:表示当前函数的括号组成样式。

                        计数器x:判断递归次数,限制其底界。

                        总的形成括号对数n。

    3.代码(力扣中国第22题)

    public List<String> generateParenthesis(int n) {
            List<String> list=new ArrayList<String>();
            add_list(list,"(", 1, n*2);       
            return list;
        }
        
        //书写递归函数
        
        public void add_list(List<String> list,String temp,int x,int n)    
        {
            x++;
            if(x<=n)
            {
              add_list(list,temp+"(",x,n);
              add_list(list,temp+")",x,n);
                
            }
            if(x>n)
            {
                //在这里写判断条件是否负荷有效的括号组合
                char[] k=temp.toCharArray();
                //计数器
                int timer=0;
                for(int i=0;i<k.length;i++)
                {
                    if(timer<0||timer>n/2)
                    {
                        return;
                    }
                    else
                    {
                        if(k[i]=='(')
                          {
                              timer++;
                          }else
                          {
                              timer--;                          
                          }
                    }             
                }
                if(timer==0)
                list.add(temp);
            }
            
        }

     

  • 相关阅读:
    Vector3函数理解-计算两向量之间的角度
    Android报错Type Error executing aapt: Return code -1
    android中 onResume()方法什么时候执行 ??(转)
    自行实现Kinect 手势Demo踩的坑
    Kinect 2.0 默认姿势的中文意思
    C#限制float有两位小数
    Android View 从左边滑出动画 ,以及从左上,左下,右上,右下放大动画。
    注册谷歌账户时最后一步验证账户输入手机号说此电话号码无法用于进行验证,如何解决?
    Mac使用sonarqube进行代码检测
    Unable to find method 'org.gradle.api.tasks.TaskInputs.file
  • 原文地址:https://www.cnblogs.com/xiaobaidashu/p/10724789.html
Copyright © 2020-2023  润新知