随想录一刷Day26——回溯算法
admin
2024-05-06 06:36:48

文章目录

  • Day26_回溯算法
    • 9. 分割回文串
    • 10. 复原 IP 地址
    • 11. 子集

Day26_回溯算法

9. 分割回文串

131. 分割回文串
思路:

  1. 回溯分割,利用回溯枚举对字符串的所有分割方案
  2. 双指针法判断回文串
class Solution {
private:vector> result;vector path;void backtracking(const string& s, int startIndex) {if (startIndex >= s.size()) {result.push_back(path);return ;}int size = s.size();for (int i = startIndex; i < size; i++) {if (isPalindrome(s, startIndex, i)) {string str = s.substr(startIndex, i - startIndex + 1);path.push_back(str);} else continue;backtracking(s, i + 1);path.pop_back();}}bool isPalindrome(const string& s, int start, int end) {for (int i = start, j = end; i < j; i++, j--) {if (s[i] != s[j]) return false;}return true;}public:vector> partition(string s) {result.clear();path.clear();backtracking(s, 0);return result;}
};

优化:

每次划分出区间重新判断回文串,出现了大量重复判断,可以利用一个数组直接将所有回文串判断出来,下次直接 O(1)O(1)O(1) 访问某区间内的字符串是否是回文串即可。

class Solution {
private:vector> result;vector path;vector> isPalindrome;void backtracking(const string& s, int startIndex) {if (startIndex >= s.size()) {result.push_back(path);return ;}int size = s.size();for (int i = startIndex; i < size; i++) {if (isPalindrome[startIndex][i]) {string str = s.substr(startIndex, i - startIndex + 1);path.push_back(str);} else continue;backtracking(s, i + 1);path.pop_back();}}void computePalindrome(const string& s) {int size = s.size();isPalindrome.resize(size, vector(size, false));for (int i = size - 1; i >= 0; i--) {for (int j = i; j < size; j++) {if (i == j) isPalindrome[i][j] = true;else if (j - i == 1 && s[i] == s[j]) isPalindrome[i][j] = true;else if (s[i] == s[j] && isPalindrome[i + 1][j - 1]) isPalindrome[i][j] = true;}}}public:vector> partition(string s) {result.clear();path.clear();computePalindrome(s);backtracking(s, 0);return result;}
};

10. 复原 IP 地址

93. 复原 IP 地址
思路:

还是枚举分割的区间,但是回溯出口是划分区间数为 4,而不是最后一次划分。

class Solution {
private:vector result;void backtracking(string& s, int startIndex, int pointNum) {if (pointNum == 3) { // 当出现三个断点,即分为 4 段if (isVaild(s, startIndex, s.length() - 1)) {result.push_back(s);}return ;}for (int i = startIndex; i < s.length(); i++) {if (isVaild(s, startIndex, i)) {s.insert(s.begin() + i + 1, '.'); // 在i的后面插入一个逗点backtracking(s, i + 2, pointNum + 1); // 插入 '.' 后,起始位置为 i + 2s.erase(s.begin() + i + 1); // 回溯删掉逗点} else break;}}bool isVaild(const string& s, int start, int end) {if (start > end) return false;if (s[start] == '0' && start != end) return false; // 前导零int num = 0;for (int i = start; i <= end; i++) {if (s[i] < '0' || s[i] > '9') return false;num = num * 10 + (s[i] - '0');if (num > 255) return false;}return true;}public:vector restoreIpAddresses(string s) {result.clear();if (s.length() < 4 || s.length() > 12) return result;backtracking(s, 0, 0);return result;}
};

11. 子集

78. 子集
思路:

如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。

直接利用回溯找组合的模板,区别就是

  1. 找子集的过程是组合问题,没有重复的
  2. 不需要结束条件,因为此过程需要枚举所有的可能,即递归所有情况后递归自动结束
class Solution {
private:vector> result;vector path;void backtracking(vector& 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();}}public:vector> subsets(vector& nums) {result.clear();path.clear();backtracking(nums, 0);return result;}
};

相关内容

热门资讯

韩国c39签证到海关会问吗?这... 韩国c39签证到海关会问吗?会问,但问题集中在行程合理性、资金证明和入境目的三个核心方向,不会涉及复...
太湖三岛住宿全攻略:含钓鱼工具... 太湖三岛住宿全攻略:含钓鱼工具与码头接送的指南 来无锡太湖,想找一处既能枕水而眠,又能享受垂钓之乐的...
1个包子卖70元?上海迪士尼回... 近日,有游客在上海迪士尼乐园内购买了一款标价为70元的“米妮蒸包”,随即引发网络热议。据网友晒出的购...
原创 如... 朋友,想在上海的饭局上装个“老克勒”(Old Money的谐音,指有品位的老上海人),别光想着学两句...
这谁发明的糊弄菜?也太好吃了吧... 今天是詹姆士的厨房陪伴你的第3572天 谢谢你的点阅与分享 小编发现最近不少外地朋友因为赏花来贵州旅...