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

相关内容

热门资讯

原创 冬... 这北风一刮,天气干冷干冷的,咱们的胃口也跟着变了。天儿一冷,就老想着吃点热乎的、扎实的,给身体攒点热...
【新城发力】辰山植物园秋冬生态... 松江新城绿环基于松江新城“北山、南水、东林、西田”的整体自然格局特征、丰富深厚的人文历史资源底蕴,提...
四川上里古镇水墨意境:二仙桥与... 你知道吗?在四川雅安的群山环抱中,藏着一座被时光遗忘的古镇。上里,这个听起来就带着诗意的地方,不是那...
俞敏洪回应全员信争议,明年将选... 三湘都市报·新湖南客户端11月20日讯(全媒体记者 卜岚 通讯员 肖昱昊 整理)今日,新东方董事长俞...
原创 安... 实拍安徽合肥包公园景区,提到这座景区,小编相信大部分人都知道,这里历史悠久,历经岁月沉淀的地方,老韵...