随想录一刷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;}
};

相关内容

热门资讯

中国六大天花板羊肉汤!各地招牌... 在中国美食版图里,一碗热气腾腾的羊肉汤,是跨越南北的冬日治愈美味。它不止是抚慰味蕾的烟火佳肴,更是扎...
茗聚泉城创新出圈 莒南茶企新品... 茶香汇泉城,创新焕新韵。5月29日,第二十届中国(济南)国际茶产业博览会暨第十四届茶文化节在济南茶叶...
荔枝泡酒怎么泡?内行人教你一步... 荔枝泡酒,作为一种既能满足味蕾又兼具仪式感的果酒制作方式,近年来备受关注。尤其是夏季荔枝大量上市,用...
原创 夏... 步入炎炎夏日,气温一天比一天高,很多长辈朋友都会出现吃不下饭、饭菜没滋味的情况。闷热天气里,油腻的大...