day28|LeetCode:● 93.复原IP地址 ● 78.子集 ● 90.子集II

题目链接:93. 复原 IP 地址

  1. 思路

切割字符串

以每次的startindex为左边界,以for循环的i为右边界

每次切割字符串判断合不合法,合法在i的后面一位加入点,当加了三个点后说明已经分成了四段,就可以停止了,但是还有最后一段没有比较,在加入结果集的时候比较,成功就加入结果集 ,再到回溯函数,再还原进行树层遍历。不符合就直接break,因为这一层不符合后面树层遍历就一定不符合

  1. 回溯法

class Solution {
public:
vector<string>result;
    void backtracking(string& s, int startindex, int pointSum) {
        if (pointSum == 3) {//说明切割成了四段
            if (isvaild(s, startindex, s.size() - 1)) result.push_back(s);//比较最后一段
             return;//返回下一行的回溯
        }
        for (int i = startindex; i < s.size(); i++) {
            if (isvaild(s, startindex, i)) {
                pointSum++;//加了点就加1
                s.insert(s.begin() + i + 1, '.');//再后面加点
                backtracking(s, i + 2, pointSum);//因为要跳过点所以再下下层再开始加点
                s.erase(s.begin() + i + 1);//回溯,到上一层
                pointSum--;//为了返回上一层还没有变过
            } else {
                break;//直接break,后面循环一定不符合
            }

        }
    }
    bool isvaild(string& s,int begin, int end) {,
        if (begin > end) return false;//当pointSum后i+2可能已经出去了,说明没有第四段,就不符合
        if (begin != end && s[begin] == '0') return false;//开头为0且不只有一个元素再这一层切割中
        int sum = 0;
        for (int i = begin; i <= end; i++) {
           if (s[i] - '0' > 9 || s[i] - '0' < 0) {//判断是不是数字
               return false;
           }
           sum = sum * 10 + s[i] - '0';
           if (sum > 255) return false;//看下ip符不符合
        }
     return true;
    }
    vector<string> restoreIpAddresses(string s) {
       backtracking(s, 0, 0);
    return result;
    }
};
  1. 递归三部曲

  • 确定递归函数参数

  • 除了需要题目给的参数外,还需要startindex来判断树枝遍历的起始位置,避免重复

  • 如果没有pointSum,只有startindex,不能判断什么时候分成了四段结束了,所以需要

  • 确定终止条件

  • 当分成了四段后我们就可以提前结束了,但是最后一段还没有比较,所以如果第四段还对u,就可以加入结果集了

  • 返回到回溯函数进行数层遍历

  • 确定单层搜索的逻辑

  • 先判断这一个分割块符不符合,不符合后面一定不符合,所以就可以break了

  • 每次遍历判断startindex和i这个阶段的分割块是否符合条件,符合条件就加入,点加1,再树枝遍历下一个分割块(递归函数)

  • 遍历完后到达不能遍历情况下返回上一层遍历不同的分割块,树层遍历。

  1. isvaild函数

比较重要的一点就是begin > end
  • 当遍历到第三段,又需要i+2=startindex进入第三层比较第四段,i+2可能超出了s的最大范围,没有第四段,所以就返回false

  1. 总结

和上一题不同的是这里可以控制分割成几段,用一个pointSum来配合。


题目链接:78. 子集

  1. 回溯法

class Solution {
public:
vector<vector<int>>result;
vector<int>path;
void backtracking(vector<int>& nums, int startindex) {
    result.push_back(path);
    for (int i = startindex; i < nums.size(); i++) {
        path.push_back(nums[i]);
        backtracking(nums, i + 1);
        path.pop_back();
    }
}
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums, 0);
        return result;
    }
};

集合问题和组合问题的差别

集合问题加入集合的时候直接加入
组合问题加入结果集中有限制

题目链接:0. 子集 II

  1. 思考

这题和组合问题II一样,都是有重复元素在元素组,但是不能重复,所以我们必须要考去重

经过推理,树枝遍历相同元素是可以加入的,树层遍历相同元素就要去除

怎么知道是什么遍历>

选择一个used数组,当树枝遍历是下一层还上一个已经遍历过了,说明是是树枝遍历可以加入

当used数组为false,说明used已经还原,进入到for循环下一层,是树层遍历

2.递归法

  1. 使用used数组

class Solution {
public:
vector<vector<int>>result;
vector<int>path;

void backtracking(vector<int>& nums, int startindex, vector<bool>& used) {
    result.push_back(path);
    for (int i = startindex; i < nums.size(); i++) {
        if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;
        path.push_back(nums[i]);
        used[i] = true;
        backtracking(nums, i + 1, used);
        used[i] = false;
        path.pop_back();
    }
}
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool>used(nums.size(), false);
        sort(nums.begin(), nums.end());
        backtracking(nums, 0, used);
        return result;
    }
};
  1. 不使用startindexz

class Solution {
public:
vector<vector<int>>result;
vector<int>path;

void backtracking(vector<int>& nums, int startindex) {
    result.push_back(path);
    for (int i = startindex; i < nums.size(); i++) {
        if (i > startindex && nums[i] == nums[i - 1]) continue;
        path.push_back(nums[i]);
        backtracking(nums, i + 1);
        path.pop_back();
    }
}
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        backtracking(nums, 0);
        return result;
    }
};
为什么这种方法也行?
  • 因为这种方法也可以判断是不是树枝遍历,当为树枝遍历时每次都是startindex==i,都是处于第一层

  • 但是当for循环遍历了,i就不等于startindex.说明是树层遍历了

  • 回溯后,一开始是树层遍历,但是startindex又按照这个i,所以下一层又是树枝遍历

  1. 递归三部曲

  • 确定递归函数的参数

  • 除了题目给的参数外,因为不能够元素重复用startindex.判断遍历方式用used数组

  • 确定终止条件

  • 因为可以到这里,集合没限制条件,就可以加入了

  • 确定单层循环的逻辑

每次加入元素就判断,符不符合条件再加入元素。进行树枝遍历,回溯再进行树层遍历

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值