首页 > 其他分享 >DAY30||491.非递减子序列 |46.全排列 |47.全排列Ⅱ

DAY30||491.非递减子序列 |46.全排列 |47.全排列Ⅱ

时间:2024-10-13 15:46:15浏览次数:3  
标签:排列 nums 46 47 used vector result path

491.非递减子序列

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

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

示例:

  • 输入: [4, 6, 7, 7]
  • 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

说明:

  • 给定数组的长度不会超过15。
  • 数组中的整数范围是 [-100,100]。
  • 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

去重逻辑是1.本层重复元素不使用,纵向的树枝可以使用重复元素,但和path末尾相比要去掉非递增的元素。(这些在单层搜索逻辑里去重,终止条件只要取所有节点即可)

 本题可以用set去重,(只记录本层重复使用的元素)。x写个上题(使用used去重)不一样的写法先。。优化可以用数组做哈希表。

 代码

class Solution {
    private:
    vector<vector<int>>result;
    vector<int>path;
    void backtraking(vector<int>&nums,int startindex)
    {
        if(path.size()>1)result.push_back(path);
        unordered_set<int>uset;
        for(int i=startindex;i<nums.size();i++)
        {
            if((!path.empty()&&nums[i]<path.back())||uset.find(nums[i])!=uset.end())//1.去掉树枝里不递增的元素2.去掉本层使用过的元素
            continue;

            path.push_back(nums[i]);
            uset.insert(nums[i]);//记录本层使用过的元素
            backtraking(nums,i+1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backtraking(nums,0);
        return result;
    }
};

46.全排列

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

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

  • 输入: [1,2,3]
  • 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

 集合有多长树就有多深,和组合问题的区别就是startindex的使用,这个的使用保证了求出的是组合。本题不需要,递归里,取完一个数,就取剩下的两个数,使用used数组记录使用过的元素。

终止条件是到达和数组同样长度即找到了一个全排列。。

代码 

class Solution {
public:
vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums,vector<bool>&used)
    {
        if(path.size()==nums.size())//全排列
        {
            result.push_back(path);
            return;
        }

        for(int i=0;i<nums.size();i++)
        {
            if(used[i]==true)continue;//纵向里使用过的元素就不重复了

            path.push_back(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            used[i]=false;
            path.pop_back();//回溯
        }

    }
    vector<vector<int>> permute(vector<int>& nums) {
        result.clear();
        path.clear();
        vector<bool>used(nums.size(),false);
        backtracking(nums,used);
        return result;

    }
};

47.全排列Ⅱ

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

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

  • 输入:nums = [1,1,2]
  • 输出: [[1,1,2], [1,2,1], [2,1,1]]

示例 2:

  • 输入:nums = [1,2,3]
  • 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

思路:本题结合了全排列Ⅰ和组合总和Ⅱ里面的去重逻辑(使用used,且这个去重一定要先对数组进行排列)。

 代码

class Solution {
public:
vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums,vector<bool>&used)
    {
        if(path.size()==nums.size())//全排列
        {
            result.push_back(path);
            return;
        }
        
        for(int i=0;i<nums.size();i++)
        {
            // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
            // used[i - 1] == false,说明同一树层nums[i - 1]使用过
            // 如果同一树层nums[i - 1]使用过则直接跳过
            if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false)continue;//这里是组合去重

            if(used[i]==false)//只有纵向递归里,没使用过的元素才取(这里是排列去重)
            {
                 path.push_back(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            used[i]=false;
            path.pop_back();//回溯

            }
           
        }

    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        result.clear();
        path.clear();
        sort(nums.begin(),nums.end());//树层去重需要对数组排序
        vector<bool>used(nums.size(),false);
        backtracking(nums,used);
        return result;

    }
};

可以感受出排列问题的不同:

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了

 一般说道回溯算法的复杂度,都说是指数级别的时间复杂度。

 切记两个去重逻辑的不同。。。

还要三道比较难的题目,这里一刷没有什么时间就先跳过了,只看了解题思路

332. 重新安排行程 - 力扣(LeetCode)

51. N 皇后 - 力扣(LeetCode)

37. 解数独 - 力扣(LeetCode)

标签:排列,nums,46,47,used,vector,result,path
From: https://blog.csdn.net/2301_79865280/article/details/142867735

相关文章

  • 18747 关键路径
    ###思路1.**建模问题**:将项目的事件和活动建模为有向无环图(DAG),其中事件是节点,活动是有权值的边。2.**选择算法**:使用拓扑排序算法来确定节点的处理顺序,然后在拓扑排序的基础上计算最长路径。3.**初始化**:创建一个入度数组来记录每个节点的入度,并创建一个距离数组来记录......
  • [Python学习日记-46] Python 中第三方开源模块的安装、使用与上传自己写的模块
    [Python学习日记-46]Python中第三方开源模块的安装、使用与上传自己写的模块简介下载与安装如何使用安装好的第三方开源模块如何上传自己写的模块到PyPi简介    在前面的模块介绍和导入当中主要介绍的都是Python内置的一些模块,我们把它称为标准库,而这个库......
  • CSP 模拟 46
    A二分答案,每个数去找范围内最左边的。B相同的数不会交换,所以设\(f_{i,j,k,u}\)为到\(i\),有了\(j\)个0,\(k\)个1,当前位置是\(u\)的最小代价,转移是暴力的,如果一个数要去前面,那么最优的方案一定不会把他往后面换,所以两次移动只有一次贡献,最终的答案要除以\(2\)。C首先......
  • 基于SaaS的小区物业管理系统设计与实现--47357(免费领源码)可做计算机毕业设计JAVA、PHP
    摘 要本论文主要论述了如何使用SpringBoot开发一个基于SaaS的小区物业管理系统小程序,本系统将严格按照软件开发流程进行各个阶段的工作,面向对象编程思想进行项目开发。在引言中,作者将论述小区物业管理系统小程序的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程......
  • B. 全排列问题
    时间限制:1s 空间限制:256MB输出自然数1到n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复的数字。(注意输出格式)输入n(1<=n<=9)输出由1~n组成的所有不重复的数字序列,每一行一个序列,每个数字前4个空格。样例样例输入13样例输出11......
  • 2146: 【例7.2】与圆相关的计算
    include<bits/stdc++.h>usingnamespacestd;doubler,pi=3.14159;intmain(){cin>>r;cout<<fixed<<setprecision(4)<<r2<<"";cout<<fixed<<setprecision(4)<<r2pi<<&quo......
  • [46] (多校联训) A层冲刺NOIP2024模拟赛06
    HDK在与mt19937_64先生的石头剪刀布比赛中拿下十一连败的好成绩你也来试试吧#include<bits/stdc++.h>usingnamespacestd;#include"include/hdk/rand.h"usingnamespacehdk::Rand;chargetchar_(){charch=getchar();if(ch>='a'andch<='z......
  • CF1746F Kazaee(随机化哈希)
    真的做不来这种题怎么办/ll题意给定\(n\)个数,\(q\)次操作:单点修改一个数的值。查询区间内所有数的出现次数是否均为\(k\)的倍数。\(n,q\le3\times10^5\)。分析一眼看上去只能带修莫队,而且常数还巨大无比。这种随机化哈希题一般是考虑一个必要不充分条件,但是充分的......
  • P9466 [EGOI2023] Bikes vs Cars / 骑车与汽车
    题意给定\(B,C\)两个矩阵,你需要构造一张两权图\(G=(V,E=\{(u,v,w_1,w_2)\})\)使得从\(i\)到\(j\)之间:可以只经过\(w_1\geB_{i,j}\)的边连通可以只经过\(w_2\geC_{i,j}\)的边连通不能只经过\(w_1>B_{i,j}\)的边连通不能只经过\(w_2>C_{i,j}\)的边连通构......
  • Codeforces Round 946 (Div. 3)
    E.MoneyBuysHappiness题意:给你\(m\)个月,每个月可以赚\(x\)元,每个月你都有一次机会花费\(c_i\)元,获得\(h_i\)的幸福。(当然你目前得有足够的钱)。求出能够获得的最大幸福值。思路:我们可以求出获得\(i\)幸福值所需的最小花费,然后判断能否有足够的钱即可。考虑如何求解,把......