LeetCode 之 Palindrome Partitioning II(动态规划)

灰太狼 2022-08-03 08:21 257阅读 0赞

【问题描述】

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",

Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

1.【基础知识】

1)substr函数掌握模糊;

2)动规与贪心算法的回顾;

3)树的深搜和广搜的应用能力;

4)fill_n函数。

2.【屌丝代码】

卡壳的地方:

1.剩下一个元素可以不切,直接判定跳出(已解决);

2.动规,一次循环同时进行前向与后向回文判定,并且采用初次前削判定和初次后削判定(已解决);

3.贪心,每次都比较,得到当下可以最快回文的长度,只不过未能实现(已解决);

4.解决了全部短小用例,倒在了代码中那段长不拉几的字符串用例上;

5.屌丝算法思想:

1)前向搜索:

1.1)先检查去掉最后Num个元素是不是回文;

1.1.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;

1.1.2)不是,继续循环体;

1.2)检查去掉最前Num个元素是不是回文;

1.2.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;

1.2.2)不是,继续循环体;

1.3)Num++

1.4)得到最终count_a;

2)后向搜索:

将1.1与1.2调换执行,得到最终count_b;

3)比较count_a与count_b,返回最小值。

  1. #include <vector>
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <vector>
  5. #include <string>
  6. using namespace std;
  7. class Solution {
  8. public:
  9. int minCut(string s)
  10. {
  11. int len = s.length();
  12. if(len<=1||IsPld(s))
  13. return 0;
  14. int tmp_len(len),cot_a(0),cot_b(0);
  15. string tmp_str = s;
  16. /*
  17. for(i=len-1;i>0;i--) // 切几刀? 如:0,表示不切,原字符串就是一个回文串
  18. {
  19. int *arr = (int*)malloc(sizeof(int)*(i+1));
  20. arr[0] = 0;
  21. vector<string> subs;
  22. for(j=1;j<=i+1;j++) // 循环刀数
  23. for(k>arr[j-1];k<) // 每一刀怎么切? 下刀点
  24. // 下一刀要比上一刀大;
  25. // 第一刀不能比0小;第一刀不能大于串长减刀数;
  26. // 第k刀不能比len-k大;
  27. // 最后一刀不能比串长大;
  28. {
  29. s.substr
  30. }
  31. delete []arr;
  32. }*/
  33. /*
  34. while(tmp_len)
  35. {
  36. if(IsPld(tmp_str.substr(0,tmp_len)))
  37. {
  38. cot_a++;
  39. tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
  40. tmp_len = tmp_str.size();
  41. if(IsPld(tmp_str))
  42. break;
  43. }
  44. else
  45. if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
  46. {
  47. cot_a++;
  48. tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
  49. tmp_len = tmp_str.size();
  50. if(IsPld(tmp_str))
  51. break;
  52. }
  53. else
  54. {
  55. tmp_len--;
  56. }
  57. }
  58. tmp_len = len;
  59. tmp_str = s;
  60. while(tmp_len)
  61. {
  62. if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
  63. {
  64. cot_b++;
  65. tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
  66. tmp_len = tmp_str.size();
  67. if(IsPld(tmp_str))
  68. break;
  69. }
  70. else
  71. if(IsPld(tmp_str.substr(0,tmp_len)))
  72. {
  73. cot_b++;
  74. tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
  75. tmp_len = tmp_str.size();
  76. if(IsPld(tmp_str))
  77. break;
  78. }
  79. else
  80. {
  81. tmp_len--;
  82. }
  83. }
  84. return min(cot_a,cot_b);
  85. */
  86. while(tmp_len)
  87. {
  88. if(IsPld(tmp_str.substr(0,tmp_len)))
  89. {
  90. cot_a++;
  91. tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
  92. tmp_len = tmp_str.size();
  93. if(IsPld(tmp_str))
  94. break;
  95. }
  96. if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
  97. {
  98. cot_a++;
  99. tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
  100. tmp_len = tmp_str.size();
  101. if(IsPld(tmp_str))
  102. break;
  103. }
  104. tmp_len--;
  105. }
  106. tmp_len = len;
  107. tmp_str = s;
  108. while(tmp_len)
  109. {
  110. if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
  111. {
  112. cot_b++;
  113. tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
  114. tmp_len = tmp_str.size();
  115. if(IsPld(tmp_str))
  116. break;
  117. continue;
  118. }
  119. if(IsPld(tmp_str.substr(0,tmp_len)))
  120. {
  121. cot_b++;
  122. tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
  123. tmp_len = tmp_str.size();
  124. if(IsPld(tmp_str))
  125. break;
  126. continue;
  127. }
  128. tmp_len--;
  129. }
  130. return min(cot_b,cot_a);
  131. }
  132. bool IsPld(string s)
  133. {
  134. if(s.length()<=1)
  135. return true;
  136. int i(0),j(s.size()-1);
  137. while(i<j)
  138. {
  139. if(s[i]!=s[j])
  140. return false;
  141. i++;
  142. j--;
  143. }
  144. return true;
  145. }
  146. };
  147. int main()
  148. {
  149. string mystr = "adabdcaebdcebdcacaaaadbbcadabcbeabaadcbcaaddebdbddcbdacdbbaedbdaaecabdceddccbdeeddccdaabbabbdedaaabcdadbdabeacbeadbaddcbaacdbabcccbaceedbcccedbeecbccaecadccbdbdccbcbaacccbddcccbaedbacdbcaccdcaadcbaebebcceabbdcdeaabdbabadeaaaaedbdbcebcbddebccacacddebecabccbbdcbecbaeedcdacdcbdbebbacddddaabaedabbaaabaddcdaadcccdeebcabacdadbaacdccbeceddeebbbdbaaaaabaeecccaebdeabddacbedededebdebabdbcbdcbadbeeceecdcdbbdcbdbeeebcdcabdeeacabdeaedebbcaacdadaecbccbededceceabdcabdeabbcdecdedadcaebaababeedcaacdbdacbccdbcece";
  150. cout<<mystr.substr(1,2)<<endl; // string.substr(首元素索引,子串长度)
  151. Solution mySln;
  152. int num = mySln.minCut(mystr);
  153. cout<<num<<endl;
  154. while(1);
  155. return 0;
  156. }

3.【源码AC】

  1. // LeetCode, Palindrome Partitioning II
  2. // 时间复杂度 O(n^2),空间复杂度 O(n^2)
  3. class Solution {
  4. public:
  5. int minCut(string s) {
  6. const int n = s.size();
  7. int f[n+1];
  8. bool p[n][n];
  9. fill_n(&p[0][0], n * n, false);
  10. //the worst case is cutting by each char
  11. for (int i = 0; i <= n; i++)
  12. f[i] = n - 1 - i; // 最后一个 f[n]=-1
  13. for (int i = n - 1; i >= 0; i--) {
  14. for (int j = i; j < n; j++) {
  15. if (s[i] == s[j] && (j - i < 2 || p[i + 1][j - 1])) {
  16. p[i][j] = true;
  17. f[i] = min(f[i], f[j + 1] + 1);
  18. }
  19. }
  20. }
  21. return f[0];
  22. }
  23. };

4.【复盘】

1)卡壳部分

  • 不能解决的原因在于字符串太长,耗时也在1H以上,题目未解出来;
  • 动规的数学式子未能很好定义提炼。

2)AC源码思想——动态规划

定义状态 f(i,j) 表示区间 [i,j] 之间最小的 cut 数,则状态转移方程为
f(i, j) = min {f(i, k) + f(k + 1, j)} , i ≤ k ≤ j,0 ≤ i ≤ j < n
这是一个二维函数,实际写代码比较麻烦。所以要转换成一维 DP。如果每次,从 i 往右扫描,每找到一个回文就算一次 DP 的话,就可以转换为

f(i) = 区间 [i, n-1] 之间最小的 cut 数

n 为字符串长度,则状态转移方程为
f(i) = min {f(j + 1) + 1} , i ≤ j < n
一个问题出现了,就是如何判断 [i,j] 是否是回文?每次都从 i 到 j 比较一遍?太浪费了,这里也是一个 DP 问题。
定义状态 P[i][j] = true if [i,j] 为回文 ,那么

P[i][j] = ( str[i] == str[j] && P[i+1][j-1] )

发表评论

表情:
评论列表 (有 0 条评论,257人围观)

还没有评论,来说两句吧...

相关阅读