首页 > 编程语言 >代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II

代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II

时间:2024-02-26 23:55:54浏览次数:31  
标签:10 排列 nums 46 随想录 int vector result 数组

491.递增子序列

题目链接:491. 非递减子序列 - 力扣(LeetCode)

思路:一开始一直报访问异常的错误,最后只好参考官网答案,结果竟然是因为我递归参数写错了导致程序一直出问题???(⊙︿⊙)

这里去重用的是标记数组,可以用集合unordered_set,但由于本题数据范围比较小,所以我们可以用数组更加高效的解决。

class Solution {
public:
    vector<vector<int>>result;
    vector<int>path;
    void backtracking(vector<int> nums,int start){
        if(path.size()>1){
            result.push_back(path);
        }
        int use[201]={0};
        for(int i=start;i<nums.size();i++){
            if((!path.empty()&&path.back()>nums[i])
                    ||use[nums[i]+100]==1){
                continue;
            }
                use[nums[i]+100]=1;
               path.push_back(nums[i]);
               backtracking(nums,i+1);
               path.pop_back();
            
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backtracking(nums,0);
        return result;
    }
};

46.全排列

题目链接:46. 全排列 - 力扣(LeetCode)

思路:利用了上一题中学到的标记数组法,用长度为6的数组记录该元素是否被使用过。注意不要在result保存结果后将数组清零,证明对回溯法理解不到位。

class Solution {
public:
    vector<vector<int>>result;
    vector<int>path;
    int count[6]={0};
    void backtracking(vector<int> nums){
        if(path.size()==nums.size()){
            result.push_back(path);
//            memset(count,0,sizeof(count));
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(count[i]){
                continue;
            }
            path.push_back(nums[i]);
            count[i]=1;
            backtracking(nums);
            count[i]=0;
            path.pop_back();
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        backtracking(nums);
        return result;
    }
};

观察题解区发现还有一种不用标记数组而是利用交换的方法。

举个简单的例子,假设我们有 [2,5,8,9,10][2, 5, 8, 9, 10][2,5,8,9,10] 这 555 个数要填入,已经填到第 333 个位置,已经填了 [8,9][8, 9][8,9] 两个数,那么这个数组目前为 [8,9 ∣ 2,5,10][8, 9~|~2, 5, 10][8,9 ∣ 2,5,10] 这样的状态,分隔符区分了左右两个部分。假设这个位置我们要填 101010 这个数,为了维护数组,我们将 222 和 101010 交换,即能使得数组继续保持分隔符左边的数已经填过,右边的待填 [8,9,10 ∣ 2,5][8, 9, 10~|~2, 5][8,9,10 ∣ 2,5] 。

当然善于思考的读者肯定已经发现这样生成的全排列并不是按字典序存储在答案数组中的,如果题目要求按字典序输出,那么请还是用标记数组或者其他方法。

class Solution {
public:
    void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){
        // 所有数都填完了
        if (first == len) {
            res.emplace_back(output);
            return;
        }
        for (int i = first; i < len; ++i) {
            // 动态维护数组
            swap(output[i], output[first]);
            // 继续递归填下一个数
            backtrack(res, output, first + 1, len);
            // 撤销操作
            swap(output[i], output[first]);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > res;
        backtrack(res, nums, 0, (int)nums.size());
        return res;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/permutations/solutions/218275/quan-pai-lie-by-leetcode-solution-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

47.全排列 II

题目链接:47. 全排列 II - 力扣(LeetCode)

思路:注意本题的去重方式,count[i-1]==0,该句的运作原理可以参照下图。其他与上一题一致。

class Solution {
public:
    vector<vector<int>>result;
    vector<int>path;
    int count[8]={0};
    void backtracking(vector<int> nums,int count[]){
        if(path.size()==nums.size()){
            result.push_back(path);
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(i&&nums[i]==nums[i-1]&&count[i-1]==0){
                continue;
            }
            if(count[i]==0){
                count[i]=1;
                path.push_back(nums[i]);
                backtracking(nums,count);
                path.pop_back();
                count[i]=0;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums){
        sort(nums.begin(),nums.end());
        backtracking(nums,count);
        return result;
    }
};

 

标签:10,排列,nums,46,随想录,int,vector,result,数组
From: https://www.cnblogs.com/Liubox/p/18035886

相关文章

  • CF464E 解题报告
    首先这是一道最短路的题目,但是数据范围十分庞大,需要高精度。但是数据范围实在太庞大了,高精度的时间复杂度是很高的,所以我们另辟蹊径。考虑到每条边边权都是\(2^x\)的形式,提示我们将起点到每个点的最短距离转化为二进制形式。考虑松弛操作需要用到什么,发现需要比较两个二进制数......
  • (29/60)递增子序列、全排列、全排列Ⅱ
    递归子序列leetcode:491.非递减子序列回溯法思路类似子集Ⅱ,每个元素大于二的节点都放入结果集。在填充path的过程中,检查是否满足非严格递增(是否等于末元素或比它大)。但是由于本题不能排序,之前的去重策略(数组排序,检查nums[i-1]==nums[i]&&used[i-1]==false)要调整......
  • day42 动态规划part4 代码随想录算法训练营 416. 分割等和子集
    题目:416.分割等和子集我的感悟:有点难,更快的解法用了01True和False所以更快理解难点:转化为背包问题听课笔记:代码示例:我优化了下classSolution:defcanPartition(self,nums:List[int])->bool:ifsum(nums)%2==1:returnFalse......
  • 代码随想录 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.0
    LeetCode:24.两两交换链表中的节点-力扣(LeetCode)思路:第一步:两两交换要考虑循环什么时候退出,当cur指针.next是null是就到尾部了,同理,链表不是奇数就是偶数,cur.next.next是空也是。第二步循环条件判断完了接下来要实现交换,如图所示,按步骤来就好,提前将1,2,3存好,接下来按图......
  • day42 动态规划part4 代码随想录算法训练营 46. 携带研究材料- 一维数组写法
    题目:46.携带研究材料我的感悟:一维是二维的压缩理解难点:倒序遍历j因为每轮的数字是由左上决定的。遍历的时候,从右侧遍历,是不会影响左侧的。听课笔记:代码示例:defbag_problem(weight,value,bagWeight):#初始化dp=[0]*(bagWeight+1)fori......
  • day42 动态规划part4 代码随想录算法训练营 卡尔网46. 携带研究材料
    题目:卡尔网-46.携带研究材料我的感悟:有1个测试用例没通过。还要多练习理解难点:dp递推公式的由来,初始化的参数。听课笔记:代码示例:defbag_problem(weight,value,bagweight):#[1,3,4][15,20,30]4ifbagweight==1:index=weigh......
  • P1462 通往奥格瑞玛的道路
    原题传送门思路首先通过读题可以发现两个量分别是血量和金钱,血量当然是越多越好,而金钱确实要最多的一次最少,一般题目说让一个量最多的时候最少,或最少的时候最多,那就会用二分来枚举这个量。那么这一题我们就会选择二分金钱,二分的条件就是到达终点的是的血量有没有大于总血量,也就......
  • 代码随想录 day61 每日温度 下一个更大元素 I
    每日温度单调栈的作用就是记录之前的元素好与当前元素比较从栈顶到栈底单调增找第一个第一个大元素单调减找第一个小元素栈内存的是数组下标而不是数组元素因为存元素还要会数组找元素是谁存下标可以直接用栈元素作为索引找数组元素下一个更大元素I跟每日温度......
  • 深度学习-卷积神经网络-经典的卷积网络incepttion-ResNet-DenceNet-46
    目录1.Inception2.ResNet3.DenseNet4.MobileNet1.Inception其中的一部分:Inception相比之前的VGGLeNet这些都是单条线的Inception多分支并行再concatInception第一版GoogleNet特征总结:NINNetworkinNetworkIncept_v3:NININ套了两次2.ResNet仅仅是......
  • POJ--3468 A Simple Problem with Integers(线段树/树状数组)
    记录11:032024-2-25http://poj.org/problem?id=1961线段树树状数组把区间增加转变为单点增加,利用两个树状数组\(c_0和c_1\)将”Clrd"转化为在树状数组\(c_0\)中,把位置l上的数加d在树状数组\(c_0\)中,把位置r+1上的数减d在树状数组\(c_1\)中,把位置l上的数......