• DAY27 93. 复原IP地址 + 78. 子集 + 90.子集II


    93. 复原IP地址

    题目要求:给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

    有效的 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" 是 无效的 IP 地址。

    示例 1:

    • 输入:s = "25525511135"
    • 输出:["255.255.11.135","255.255.111.35"]

    示例 2:

    • 输入:s = "0000"
    • 输出:["0.0.0.0"]

    示例 3:

    • 输入:s = "1111"
    • 输出:["1.1.1.1"]

    示例 4:

    • 输入:s = "010010"
    • 输出:["0.10.0.10","0.100.1.0"]

    示例 5:

    • 输入:s = "101023"
    • 输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

    提示:

    • 0 <= s.length <= 3000
    • s 仅由数字组成

    思路

    其实只要意识到这是切割问题,切割问题就可以使用回溯搜索法把所有可能性搜出来,和刚做过的131.分割回文串 (opens new window)就十分类似了。

    1. class Solution {
    2. public:
    3. vector res;
    4. void backtracking(string& s, int startIndex, int pointNum) {
    5. if (pointNum == 3) {
    6. if (isValid(s, startIndex, s.size() - 1)) {
    7. res.push_back(s);
    8. }
    9. return;
    10. }
    11. for (int i = startIndex; i < s.size(); i++) {
    12. if (isValid(s, startIndex, i)) {
    13. s.insert(s.begin() + i + 1, '.');
    14. pointNum++;
    15. backtracking(s, i + 2, pointNum);
    16. pointNum--;
    17. s.erase(s.begin() + i + 1);
    18. } else break;
    19. }
    20. }
    21. bool isValid(const string& s, int start, int end) {
    22. if (start > end) return false;
    23. if (s[start] == '0' && start != end) return false;
    24. int num = 0;
    25. for (int i = start; i <= end; i++) {
    26. if (s[i] > '9' || s[i] < '0') return false;
    27. num = num * 10 + (s[i] - '0');
    28. if (num > 255) return false;
    29. }
    30. return true;
    31. }
    32. vector restoreIpAddresses(string s) {
    33. res.clear();
    34. if (s.size() < 4 || s.size() > 12) return res;
    35. backtracking(s, 0, 0);
    36. return res;
    37. }
    38. };
    • 时间复杂度: O(3^4),IP地址最多包含4个数字,每个数字最多有3种可能的分割方式,则搜索树的最大深度为4,每个节点最多有3个子节点。
    • 空间复杂度: O(n)

    78. 子集

    题目要求:给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    说明:解集不能包含重复的子集。

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

    思路

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

    有同学问了,什么时候for可以从0开始呢?

    求排列问题的时候,就要从0开始,因为集合是有序的,{1, 2} 和{2, 1}是两个集合,排列问题我们后续的文章就会讲到的。

    以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:

    不要收集两遍(在终止条件中收集又在回溯之前收集)

    1. class Solution {
    2. public:
    3. vector<int> path;
    4. vectorint>> res;
    5. void backtracking(const vector<int>& nums, int startIndex) {
    6. // 收集子集,要放在终止添加的上面,否则会漏掉自己
    7. res.push_back(path);
    8. if (startIndex >= nums.size() || path.size() == nums.size()) {
    9. return;
    10. }
    11. for (int i = startIndex; i < nums.size(); ++i) {
    12. path.push_back(nums[i]);
    13. backtracking(nums, i + 1);
    14. path.pop_back();
    15. }
    16. }
    17. vectorint>> subsets(vector<int>& nums) {
    18. path.clear();
    19. res.clear();
    20. backtracking(nums, 0);
    21. return res;
    22. }
    23. };

    90. 子集II

    题目要求:

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

    说明:解集不能包含重复的子集。

    示例:

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

    思路

    首先是排序,把一样的元素汇集在一起,然后是需要有一个Bool数组或者StartIndex来控制同一层不能有一样的元素。

    1. class Solution {
    2. public:
    3. vector<int> path;
    4. vectorint>> res;
    5. void backtracking(const vector<int>& nums, int startIndex, vector<bool> used) {
    6. res.push_back(path);
    7. if (startIndex > nums.size() || path.size() == nums.size()) return;
    8. for (int i = startIndex; i < nums.size(); ++i) {
    9. if (i > 0 && nums[i] == nums[i-1] && used[i-1] == false) continue;
    10. path.push_back(nums[i]);
    11. used[i] = true;
    12. backtracking(nums, i+1, used);
    13. used[i] = false;
    14. path.pop_back();
    15. }
    16. }
    17. vectorint>> subsetsWithDup(vector<int>& nums) {
    18. path.clear();
    19. res.clear();
    20. vector<bool> used(nums.size(), false);
    21. sort(nums.begin(), nums.end());
    22. backtracking(nums, 0, used);
    23. return res;
    24. }
    25. };

  • 相关阅读:
    redis高可用
    如何用JVS的低代码进行配置管理?模板打印详细介绍
    第十九章绘图
    【个人博客搭建】(24)统一api接口返回格式
    【STM32】PWM输出
    LeetCode-152. 乘积最大子数组
    嵌入式学习笔记(41)实时时钟RTC
    探索React未来:预期特性与开发者前瞻
    JSONObject将json字符串转成java嵌套对象
    快速排序和归并排序非递归的详解
  • 原文地址:https://blog.csdn.net/fuxxu/article/details/133937987