131.分割回文串
题目链接:. - 力扣(LeetCode)
讲解视频:131.分割回文串
题目描述:
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是回文串 。返回 s
所有可能的分割方案。
示例 1:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]]
解题思路:
深度:由当前字符串所含字母个数决定。当递归至字符串末尾即startIdx==字符串s长度时返回
宽度:由当前字符串所含字母个数决定。使用startIdx和i来确定子串范围。若子串不是回文串,就continue
代码:
class Solution {
public:
vector<vector<string>> result;
vector<string> path;
bool isPalindromicString(string sub)
{
for(int i = 0, j = sub.size()-1; i<j; i++,j--)
if(sub[i] != sub[j]) return false;
return true;
}
void Backtracking(string s, int startIdx)
{
if(startIdx == s.size())
{
result.push_back(path);
return;
}
for(int i = startIdx; i < s.size(); i++)
{
string sub = s.substr(startIdx,i - startIdx + 1);
if(isPalindromicString(sub))
{
path.push_back(sub);
}
else continue;
Backtracking(s,i+1);
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
Backtracking(s,0);
return result;
}
};
93.复原IP地址
题目链接:. - 力扣(LeetCode)
讲解视频:
回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原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 地址。
给定一个只包含数字的字符串 s
,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s
中插入 '.'
来形成。你 不能 重新排序或删除 s
中的任何数字。你可以按 任何 顺序返回答案。
示例 1:
输入:s = "25525511135" 输出:["255.255.11.135","255.255.111.35"]
示例 2:
输入:s = "0000" 输出:["0.0.0.0"]
解题思路:
深度:以‘.’的个数作为深度,最多3个‘.’,深度最大为3(根深度为0)
宽度:本题中宽度最多为3。而且截取出的数需满足题目要求
剪枝:同一层中当子串满足如下任意一个条件时该层就停止遍历:
- 以0开头且长度不为1
- 长度>=3且值超过255
代码:
class Solution {
public:
vector<string> result;
bool isValid(string s, int start, int end)
{
if(start > end) return false;
if(s[start] == '0' && start != end) return false;
int sum = 0;
for(int i = start; i <= end; i++)
{
char c = s[i];
if(c < '0' || c > '9') return false;
sum = sum*10 + (c - '0');
if(sum > 255) return false;
}
return true;
}
void backTracking(string& s, int startIdx, int pointSum)
{
if(pointSum == 3)
{
if(isValid(s,startIdx, s.size()-1)) result.push_back(s);
return;
}
for(int i = startIdx; i < s.size(); i++)
{
if(isValid(s,startIdx,i))
{
s.insert(s.begin()+i+1,'.');
pointSum++;
backTracking(s,i+2,pointSum);
pointSum--;
s.erase(s.begin()+i+1);
}
else break;
}
}
vector<string> restoreIpAddresses(string s) {
result.clear();
if(s.size() < 4 || s.size() > 12) return result;
backTracking(s,0,0);
return result;
}
};
78.子集
题目链接:. - 力扣(LeetCode)
讲解视频:
回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集
题目描述:
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0] 输出:[[],[0]]
解题思路:
与分割题类似,唯一不同点在于该题目除根节点以外的节点都要保存,之前做的题只保存叶子节点
代码:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backTracking(vector<int>& nums, int startIdx)
{
result.push_back(path);
if(startIdx >= nums.size()) return ;
for(int i = startIdx; i < nums.size(); i++)
{
path.push_back(nums[i]);
backTracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
result.clear();
backTracking(nums,0);
return result;
}
};
90.子集II
题目链接:. - 力扣(LeetCode)
讲解视频:
回溯算法解决子集问题,如何去重?| LeetCode:90.子集II
题目描述:
给你一个整数数组 nums
,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:
输入:nums = [0] 输出:[[],[0]]
解题思路:
该题目是要在前一题的基础上增加去重操作,同一棵树相同元素不去重,不同子树同一层相同元素要去重。有如下两种方法:
- set去重-->根据set中不会保存重复元素的特点,对不同子树同一层重复元素进行去重
- used数组去重-->方法同回溯组合篇--代码随想录算法训练营第二十一天的40.组合总和II题
代码:
1、set方法
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backTracking(vector<int>& nums, int startIdx)
{
result.push_back(path);
if(startIdx >= nums.size()) return;
unordered_set<int> isdup;
for(int i =startIdx; i < nums.size(); i++)
{
if(isdup.find(nums[i]) != isdup.end()) continue;
path.push_back(nums[i]);
isdup.insert(nums[i]);
backTracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
result.clear();
path.clear();
sort(nums.begin(),nums.end());
backTracking(nums,0);
return result;
}
};
2、used数组判断法
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backTracking(vector<int>& nums, int startIdx, vector<int>& used)
{
result.push_back(path);
if(startIdx >= nums.size()) return;
for(int i =startIdx; i < nums.size(); i++)
{
if(i > 0 && nums[i] == nums[i-1] && used[i-1] == 0) continue;
path.push_back(nums[i]);
used[i] = 1;
backTracking(nums,i+1,used);
used[i] = 0;
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
result.clear();
path.clear();
vector<int> used(nums.size(),0);
sort(nums.begin(),nums.end());
backTracking(nums,0,used);
return result;
}
};