回溯算法实现

回溯算法实现,第1张

什么是回溯算法

就是在递归算法的基础上加上回溯条件。


怎么样写回溯算法(从上而下,※代表难点,根据题目而变化)
①画出递归树,找到状态变量(回溯函数的参数),这一步非常重要※
②根据题意,确立结束条件
③找准选择列表(与函数参数相关),与第一步紧密关联※
④判断是否需要剪枝
⑤作出选择,递归调用,进入下一层
⑥撤销选择

void backtrack(路径,选择列表)
{
    if(终止条件)
    {
       收集结果;
       return返回;
    }
    for(集合元素)
    {
       ;
       递归函数;
       回溯 *** 作;//比如插销节点元素
    }
}

1,以下是用for循环实现的:

原理:就是每次从容器中取一个元素,再循环取之前所有的子集,把这个元素加入每一个子集,就得到新的子集。


注意:

myv[j].push_back(num[i]);

这是在原来容器的基础上直接插入,原来的容器就不在了,想要保留原来的容器,应该是赋值当前容器的一个副本,在这个副本里插入,如下:

class Solution {
public:
    vector> subsets(vector& nums) {
    int i=0,j=0;
    vector>myv;
    if(nums.size()==0)
        return myv;
    vector temp;
    for(;i
容器之间的赋值

容器之间的赋值,赋的是容器的值,不包含这个容器的地址信息,改变一个不影响另一个。


2,回溯实现子集

回溯算法实现子集原理:

一条路走到低,再从底层退出,每退一层,走完这一层的所有路径,再退回上一层。


void backtrack(vectornums,vector&path,int next)
{
    res.push_back(path);//把之前已经插入好的容器插入存放容器的容器中
    for(int i=start;i



    {
        path.push_back(nums[i]);//把下一层第i条路径的第一个元素推入一个容器
        backtrack(nums,path,i+1);//递归进入下一层(取下一个元素),注意i+1,标识下一个选择列表的开始位置,最重要的一步,这里所有传递过去的实参都是值赋值传递,而且每进入下一次,path中都含有上一层的元素。



        path.pop_back();//当退出时,因为要进入另外一条路径,所以要取出走过路径的元素
    }
}

本层的每一层循环就是本层的另外一条路径。


每一次进入下一层都要先加入下一层的元素,形成新子集加入容器,并带入下一层;

每一次从下一层退出,都要将本层加入的下一层元素清除,再选择另外一条路径,再加入那条路径的元素,重复以上过程,直到走完每一条路径的低,再从低退一层,走完每一层所有路径,再退回上一层,直到完成所有路径。


注意:pop_back只是清除在本层加入的元素,退出(回溯)是backtrack退出,才是退出,并不是指向完pop_back就退出,还要判断条件。


变量i既表示同级的路径,也表示每一条路径可以达到的深度。


深度值是在路径值基础上加1

class Solution {

public:

    vector>myv;

    vectorsonv;

    void backtrack(vector&nums,vector&sonv,int next)

    {

        myv.push_back(sonv);

        for(int i=next;i

        {

            sonv.push_back(nums[i]);

            backtrack(nums,sonv,i+1);

            sonv.pop_back();

        }

    }

    vector> subsets(vector& nums) {

    if(nums.size()==0)

        return myv;

    vector temp;

    backtrack(nums,sonv,0);

    return myv;

    }

};

含有重复元素子集

leetcode--90题

   void backtracking(vector& nums, int startIndex, vector& used) {
        result.push_back(path);
        for (int i = startIndex; i < nums.size(); i++) {
            // used[i - 1] == true,说明同一树支candidates[i - 1]使用过
            // used[i - 1] == false,说明同一树层candidates[i - 1]使用过
            // 而我们要对同一树层使用过的元素进行跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            path.push_back(nums[i]);
            used[i] = true;
            backtracking(nums, i + 1, used);
            used[i] = false;
            path.pop_back();
        }
    }

有一点需要注意:

只要排好序,就不会出现,同层具有相同值,而后面不同的情况,分支少的那一支在前面的分支一定已经有过了,所以我们遇到统计重复的,就不必继续了,往下一个路径走。


nums[i] == nums[i - 1]

这个是判断同一个节点下一层的不同路径的第一个值是否相同

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/565228.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-06
下一篇 2022-04-06

发表评论

登录后才能评论

评论列表(0条)