回溯法简单示例

演示回溯法最常用的例子应该就是
全排列、组合和、回文分区了(Subsets, Permutations, Combination Sum, Palindrome Partioning)

Permutations

Combination Sum
Palindrome Partioning
Subsets
以上是相应的Leetcode题目地址。

就以Permutation为例

Given a collection of distinct numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

意思就是给一系列不重复的数字nums,返回他们的全排列,现在暂时不考虑重复问题

思路就是 先固定第一个数,然后以此数为结点依次往下,然而固定第二个数,当到达叶子时(即长度为nums的长度),就将结果保存,然后往回走,挨个pop_back,其实就是深度优先搜索,看代码就可以明白了。

class Solution
{
    vector<vector<int>> result;//放外面纯粹是懒
public:

    void helper(vector<int>& vec, vector<bool>& visited, vector<int>& cur)
    {
        if (cur.size() == vec.size()) 
        {
            result.push_back(cur); //cur的长度等于vec长度显然就到达叶子节点了
            return;
        }
        for (int i = 0; i < vec.size(); ++i)
        {
            if (visited[i] == false) //visited用于固定数字
            {
                visited[i] = true;
                cur.push_back(vec[i]);      
                helper(vec, visited, cur); //到达1 2 3 后
                cur.pop_back();            //此处将3弹出,之后的同理

                visited[i] = false;
            }
        }
    }


    vector<vector<int>> permute(vector<int>& nums)
    {
        if (nums.size() == 0)
            return result;
        vector<bool> visited(nums.size(), false);
        vector<int> cur;
        helper(nums, visited, cur);
        return result;
    }
};
其进阶版 就 存在 重复的数duplicate


Given a collection of numbers that might contain duplicates, return all possible unique permutations.

For example,
[1,1,2] have the following unique permutations:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]
大致的框架还是没变的,但要考虑到跳过重复元素的问题
首先将数进行排序,方便进行重复元素判断
当判断第i个元素是否是重复的元素时,判断i-1是否被固定且i和i-1元素是否相等,若其前一个元素与之相等且未被使用过,那么显然就跳过当前元素,重复元素的使用应当是有序的。
然后和上面版本一样判断i元素是否被固定
class Solution {
public:
    vector<vector<int>>result;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        if(nums.size()==0)
            return result;
        sort(nums.begin(),nums.end());
        vector<int>cur;
        vector<bool>used(nums.size(),false);
        backTrack(nums,cur,used);
        return result;
    }
    void backTrack(vector<int>&nums,vector<int>&cur,vector<bool>&used){
        if(cur.size()==nums.size())
        {
            result.push_back(cur);
            return;
        }
        for(int i = 0;i<nums.size();++i){
            if(used[i]||i>0&&!used[i-1]&&nums[i]==nums[i-1])//多出来的就这部分,判断是否重复且前一个元素未使用
                continue;

            used[i] = true;
            cur.push_back(nums[i]);
            backTrack(nums,cur,used);
            cur.pop_back();
            used[i] = false;

        }

    }
};

其他题目都大同小异了,都有一个一个基本的框架,然后根据题目填就是了

    原文作者:回溯法
    原文地址: https://blog.csdn.net/MaloryVer9/article/details/78159138
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞