代码随想录-回溯算法(子集问题)|ACM模式

这篇具有很好参考价值的文章主要介绍了代码随想录-回溯算法(子集问题)|ACM模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言:

78. 子集

题目描述:

输入输出描述:

思路和想法:

90. 子集 II

题目描述:

输入输出描述:

思路和想法:

491. 递增子序列

题目描述:

输入输出描述:

思路和想法:


前言:

如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点

子集是无序的,取过的元素不会重复取,写回溯算法的时候,for就要从Index开始。

之后讨论的问题,分为两种:

  • 集合里无重复元素
  • 集合里有重复元素,求取的子集需要进行去重(可排序)
  • 集合中找递增子集(不可排序)

78. 子集

题目描述:

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

输入输出描述:

示例1:

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

示例2:

输入:nums = [0] 输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

思路和想法:

这一道题是模板题,可以从这道题感受子集问题解法与之前的不同。

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 78. 子集
* */
vector<vector<int>> result;
vector<int> path;

/*
* 函数:          backtracing()
* 输入参数:       s:输入的字符串    index:数组元素下标
* */
void backtracing(vector<int> &nums,int Index){
    result.push_back(path);
    //回溯过程
    for (int i = Index; i < nums.size(); ++i) {
        path.push_back(nums[i]);
        backtracing(nums,i + 1);
        path.pop_back();
    }
};


int main() {
    result.clear();
    path.clear();

    int num;
    vector<int> nums;
    while(cin>>num){
        nums.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    backtracing(nums,0);
    cout << "[";
    for (int i = 0; i < result.size(); ++i) {
        cout << "[";
        for (int j = 0; j < result[i].size(); ++j) {
            cout<< result[i][j];
            if(j != result[i].size() - 1) cout << ",";
        }
        cout << "]";
        if(i != result.size() - 1)  {cout << ",";}
    }
    cout << "]";
    return 0;
}

/*  测试样例
1 2 3

0
*
* */

90. 子集 II

题目描述:

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

输入输出描述:

示例1:

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

示例2:

输入:nums = [0] 输出:[[],[0]]

提示:

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

思路和想法:

这道题目和上一道题之间的区别:集合里有了重复元素,而且求取的子集要进行去重。

所以在上一道题的基础上,引入树层去重,这道题目可以参考回溯算法中组合问题里的40.组合总和II。

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 90. 子集II
* */
vector<vector<int>> result;
vector<int> path;

/*
* 函数:          backtracing()
* 输入参数:       s:输入的字符串    index:数组元素下标  used:使用过的标志
* */
void backtracing(vector<int> &nums,int Index, vector<bool> used){
    result.push_back(path);
    //回溯过程
    for (int i = Index; i < nums.size(); ++i) {
        // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
        // used[i - 1] == false,说明同一树层nums[i - 1]使用过
        // 这里注意树层和树枝的区别,这里我们是对树层进行跳过。
        if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false){
            continue;
        }
        path.push_back(nums[i]);
        used[i] = true;
        backtracing(nums,i + 1,used);
        used[i] = false;
        path.pop_back();
    }
};


int main() {
    result.clear();
    path.clear();

    int num;
    vector<int> nums;
    while(cin>>num){
        nums.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }
    vector<bool> used(nums.size(), false);
    sort(nums.begin(),nums.end());
    backtracing(nums,0,used);

    //输出模式
    cout << "[";
    for (int i = 0; i < result.size(); ++i) {
        cout << "[";
        for (int j = 0; j < result[i].size(); ++j) {
            cout<< result[i][j];
            if(j != result[i].size() - 1) cout << ",";
        }
        cout << "]";
        if(i != result.size() - 1)  {cout << ",";}
    }
    cout << "]";
    return 0;
}

/*  测试样例
1 2 2

0
*
* */

491. 递增子序列

题目描述:

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

输入输出描述:

示例1:

输入:nums = [4,6,7,7] 输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

示例2:

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

提示:

  • 1 <= nums.length <= 15
  • -100 <= nums[i] <= 100

思路和想法:

这道题目相较于上一道题子集II有什么区别,这道题是要在数组中找到不同的递增子序列,所以不能对原数组进行排序

所以去重的方法,不能用原来的逻辑,这道题目还是进行树层去重,这里采用set来实现。文章来源地址https://www.toymoban.com/news/detail-618247.html

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 491. 递增子序列
* */
vector<vector<int>> result;
vector<int> path;

/*
* 函数:          backtracing()
* 输入参数:       s:输入的字符串    index:数组元素下标
* */
void backtracing(vector<int> &nums,int Index){
    if(path.size() > 1){
        result.push_back(path);
    }
    //回溯过程
    unordered_set<int> uset;    //使用set对本层元素进行去重,新的一层会重新定义清空的
    for (int i = Index; i < nums.size(); ++i) {
        if((!path.empty() && nums[i] < path.back()) || uset.find(nums[i]) != uset.end()){
            continue;
        }

        uset.insert(nums[i]);
        path.push_back(nums[i]);
        backtracing(nums,i + 1);
        path.pop_back();
    }
};


int main() {
    result.clear();
    path.clear();

    int num;
    vector<int> nums;
    while(cin>>num){
        nums.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    backtracing(nums,0);

    //输出模式
    cout << "[";
    for (int i = 0; i < result.size(); ++i) {
        cout << "[";
        for (int j = 0; j < result[i].size(); ++j) {
            cout<< result[i][j];
            if(j != result[i].size() - 1) cout << ",";
        }
        cout << "]";
        if(i != result.size() - 1)  {cout << ",";}
    }
    cout << "]";
    return 0;
}

/*  测试样例
4 6 7 7

4 4 3 2 1
*
* */

到了这里,关于代码随想录-回溯算法(子集问题)|ACM模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 代码随想录算法训练DAY27|回溯3

    力扣题目链接 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明: 所有数字(包括 target)都是正整数。 解集不能包含重复的组合。 示例 1: 输入:candidates = [2,3,6,

    2024年01月23日
    浏览(28)
  • 代码随想录day42|背包问题、416. 分割等和子集

     背包问题:    01 背包 二维数组dp[i][j]解法 纯01背包:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。 每件物品只能用一次 ,求解将哪些物品装入背包里物品价值总和最大。 dp[i][j]:从下标为[0-i]的物品里任意取,放进容量为j的

    2024年04月09日
    浏览(37)
  • 代码随想录 - Day34 - 回溯:递增子序列+排列问题

    如果有相等的整数也算递增序列 递增子序列中 至少有两个元素 (遍历的时候不用遍历 nums 中最后一个元素) 题目说了数值范围,所以还可以用哈希表去重,速度比 set() 快很多。 但是,个人觉得没必要,因为放在实际情况中一般不会给数值范围。 全排列,即 [1,2] 和 [2,1] 算作

    2024年02月09日
    浏览(52)
  • 代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集

    说到背包问题大家都会想到使用动规的方式来求解,那么为什么用动规呢, dp数组代表什么呢 ? 初始化是什么 , 遍历方式又是什么 ,这篇文章笔者将详细讲解背包问题的经典例题0-1背包问题和完全背包问题的解题方式,希望能帮助到大家 有人一提到背包问题就只会使用动态规划来

    2024年02月06日
    浏览(43)
  • 代码随想录23| 93.复原IP地址, 78.子集, 90.子集II

    题目链接/文章讲解:链接地址 视频讲解:链接地址 题目链接/文章讲解:链接地址 视频讲解:链接地址 题目链接/文章讲解:链接地址 视频讲解:链接地址

    2024年02月11日
    浏览(72)
  • 代码随想录——回溯

    代码随想录——回溯 回溯的本质就是递归遍历,但在完成某一条路之后会撤回到上一层,然后重新选择另一条路继续遍历,是一个比较低效的算法,能进行提升的方式就是剪枝。 组合 链接:https://leetcode.cn/problems/combinations/description/ vectorvector int 作为最终返回的结果,vector

    2024年01月19日
    浏览(30)
  • 代码随想录二刷 |回溯 |分割回文串

    131.分割回文串 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。 返回 s 所有可能的分割方案。 示例: 输入: “aab” 输出: [ [“aa”,“b”], [“a”,“a”,“b”] ] 回溯三部曲 递归函数参数 全局变量数组path存放切割后回文的子串,二维数组result存放结果集 参数

    2024年01月24日
    浏览(28)
  • 代码随想录阅读笔记-回溯【电话号码的字母组合】

    题目 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例: 输入:\\\"23\\\" 输出:[\\\"ad\\\", \\\"ae\\\", \\\"af\\\", \\\"bd\\\", \\\"be\\\", \\\"bf\\\", \\\"cd\\\", \\\"ce\\\", \\\"cf\\\"]. 说明:尽管上面的答案是按字典序排列的,但是你可以任意

    2024年04月13日
    浏览(24)
  • 【Day42】代码随想录之动态规划0-1背包_416. 分割等和子集

    动态规划理论基础 动规五部曲: 确定dp数组 下标及dp[i] 的含义。 递推公式:比如斐波那契数列 dp[i] = dp[i-1] + dp[i-2]。 初始化dp数组。 确定遍历顺序:从前到后or其他。 推导dp数组。 出现结果不正确: 打印dp日志和自己想的一样:递推公式、初始化或者遍历顺序出错。 打印

    2024年02月20日
    浏览(38)
  • 代码随想录刷题笔记 DAY 28 | 复原 IP 地址 No.93 | 子集 No.78 | 子集 II No.90

    01. 复原 IP 地址(No. 93) 题目链接 代码随想录题解 1.1 题目 有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0 ),整数之间用 \\\'.\\\' 分隔。 例如: \\\"0.1.2.201\\\" 和 \\\"192.168.1.1\\\" 是 有效 IP 地址,但是 \\\"0.011.255.245\\\" 、 \\\"192.168.1.312\\\" 和 \\\"192.168@1.1\\\" 是 无效 I

    2024年02月22日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包