学习目标:
博主介绍: 27dCnc
专题 : 数据结构帮助小白快速入门
👍👍👍👍👍👍👍👍👍👍👍👍
☆*: .。. o(≧▽≦)o .。.:*☆
学习时间:
- 周一至周五晚上 7 点—晚上9点
- 周六上午 9 点-上午 11 点
- 周日下午 3 点-下午 6 点
主题: 回溯算法
今日份打卡
- 代码随想录-回溯算法
学习内容:
- 复原IP地址
- 子集
- 子集II
内容详细
93.复原IP地址
题目考点 : IP基础知识
回溯
条件判断
隔板法
题目分析: 本题也是查用隔板法将各个数据隔开,然后判断每个隔开的数据最后得到答案
判断子串是否合法
最后就是在写一个判断段位是否是有效段位了。
主要考虑到如下三点:
- 段位以0为开头的数字不合法
- 段位里有非正整数字符不合法
- 段位如果大于255了不合法
回溯三部曲
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}
详细请看文章 : 回溯算法基础
最后代码
class Solution {vector<string>result; void backtricking(string&s,int StartIndex,int poinSum) { //pointSum是逗点的统计if(poinSum == 3) { // 终止条件if(isGood(s, StartIndex, s.size() - 1)) {result.push_back(s);}return ;}for(auto i = StartIndex; i < s.size();i++) {if(isGood(s,StartIndex,i)) {s.insert(s.begin() + i + 1, '.');poinSum++;backtricking(s, i+2, poinSum);poinSum--;s.erase(s.begin() + i + 1);} else break;}}bool isGood(const string& s, int start, int end) {if (start > end) {return false;}if (s[start] == '0' && start != end) {return false;}int num = 0;for(auto i = start; i<= end; i++) {if (s[i] > '9' || s[i] < '0') {return false;}num = num * 10 + (s[i] - '0');if (num > 255) {return false;}}return true;}
public:vector<string> restoreIpAddresses(string s) {result.clear();if (s.size() < 4 || s.size() > 12) return result;backtricking(s,0,0);return result;}
};
78.子集
题目考点: 集合子集
组合
回溯收集路径
解题思路
如果把子集问题、组合问题、分割问题都抽象为一棵树 的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。
那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!
所以运到集合问题时我们用 startIndex
去控制我们遍历顺序,遍历的位置开始,
题目回溯图
题解代码
class Solution {
private:vector<vector<int>> result;vector<int>v;
public:void backtracking(vector<int>&nums,int startIndex) {result.push_back(v); //收集路径if (startIndex >= nums.size()) {return ;}for(auto i = startIndex;i < nums.size(); ++i) {v.push_back(nums[i]);backtracking(nums,i+1);v.pop_back();}}vector<vector<int>> subsets(vector<int>& nums) {result.clear(),v.clear();backtracking(nums,0);return result;}
};
90.子集II
题目考点: 回溯
子集
回溯路径收集
回溯去重
题目思路
这个题目考点便是, 子集可以按照任意顺序排列
这个说明我们取的元素不可以重复,但是我们的集合也不能重复,这个便是题目的考点,我们可以取同一个元素多次,但是最后组合成的结果不能出现重复,这个时候我们就要取重,关于去重方法我们可以采用标记法
关键图解
最后题目代码
class Solution {
private:vector<vector<int>>result;vector<int>vec;
public:void backtracking(vector<int>&nums,int StratIndex,vector<bool>& used) {result.push_back(vec);// used[i-1] ==true,说明同一树枝candidates[i-1]使用过// used[i-1] ==false,说明同一树层candidates[i-1]使用过//而我们要对同一树层使用过的元素进行跳过for(auto i = StratIndex; i < nums.size(); ++i) {if (i>0 && nums[i] == nums[i-1] && used[i-1] == false) {continue;}vec.push_back(nums[i]);used[i] = true;backtracking(nums,i+1,used);used[i] = false;vec.pop_back();}}
public:vector<vector<int>> subsetsWithDup(vector<int>& nums) {result.clear(),vec.clear();vector<bool> used(nums.size(),false);sort(nums.begin(),nums.end());backtracking(nums,0,used);return result;}
};
使用set去重的方法
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {result.push_back(path);unordered_set<int> uset;for (int i = startIndex; i < nums.size(); i++) {if (uset.find(nums[i]) != uset.end()) {continue;}uset.insert(nums[i]);path.push_back(nums[i]);backtracking(nums, i + 1);path.pop_back();}}public:vector<vector<int>> subsetsWithDup(vector<int>& nums) {result.clear();path.clear();sort(nums.begin(), nums.end()); // 去重需要排序backtracking(nums, 0);return result;}
关于去重
去重的方法有很多但是我们最后和目的只要一个,怎么简单怎么来
也可以这样写
if (i > startIndex && nums[i] == nums[i - 1] ) {continue;
}
题型总结
学习产出:
- 技术笔记 2 遍
- CSDN 技术博客 3 篇
- 习的 vlog 视频 1 个
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~