0.该算法同时使用,有重复的全排列,无重复的全排列,字符串全排列,但需要注意的是字符串全排列传递的参数以及预设的变量不同,eg vetcor<string
1.考虑重复的情况,逐个分支去遍历。弄懂算法。
2.再次基础上 理解if(i > 0 && num[i - 1] == num[i] && !vis[i - 1]),//当前的元素num[i]与同一层的前一个元素num[i-1]相同且num[i-1]已经用过了
出现此种情况可以舍弃分支,但这一定是建立再已经sort的基础上的。所以不管题目是否要求按字典大或小顺序输出都得排序,换句话说,该算法输出的结果一定是按照字典排序的。数注意该算法与前面的交换法时间复杂度、空间复杂度一样,前者胜在 代码结构简单。
class Solution {
public:
    void recursion(vector<vector<int> > &res, vector<int> &num, vector<int> &temp, vector<int> &vis){
        //临时数组满了加入输出
        if(temp.size() == num.size()){
            res.push_back(temp);
            return;
        }
        //遍历所有元素选取一个加入
        for(int i = 0; i < num.size(); i++){
            //如果该元素已经被加入了则不需要再加入了
            if(vis[i])                            //控制循环
                continue;
            if(i > 0 && num[i - 1] == num[i] && !vis[i - 1])      //剪枝
                //当前的元素num[i]与同一层的前一个元素num[i-1]相同且num[i-1]已经用过了
                continue; 
            //标记为使用过
            vis[i] = 1; 
            //加入数组
            temp.push_back(num[i]);
            recursion(res, num, temp, vis);
            //回溯
            vis[i] = 0;
            temp.pop_back();
        }
    }
     
    vector<vector<int> > permuteUnique(vector<int> &num) {
        //先按字典序排序
        sort(num.begin(), num.end());
        //标记每个位置的元素是否被使用过
        vector<int> vis(num.size(), 0);//vector初始化语法,指定长度为。size,且每个元素赋初值为0
        vector<vector<int> > res;//传引用仅作为输出二位容器用
        vector<int> temp;//记录当前暂存递归过程中组装的排列情况。
                                    使用额外的vis数组用于记录哪些位置的数字被加入了。
        //递归获取
        recursion(res, num, temp, vis);
        return res;
    }
};