博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[LeetCode] Longest Palindromic Substring
阅读量:7127 次
发布时间:2019-06-28

本文共 4909 字,大约阅读时间需要 16 分钟。

This problem has a long story. There are just too many solutions on the web and it can be studied for a long time before you fully grasp it. Morever, it can induce many other concepts or problems (longest palindromic subsequence, longest common substring, etc).

The simplest way to solve it is to use two-dimensional DP. We denote P[i][j] to be an indicator of whether the substring from i to j (inclusive) is a palindrome. It is obvious that the following relationships hold:

  1. P[i][i] = 1 (each character itself is palindromic);
  2. P[i][i + 1] = s[i] == s[j] (two neighboring characters are palindromic if they are the same);
  3. P[i][j] = P[i + 1][j - 1] && s[i] == s[j] (If the substring is palindrome, then adding the same character at both of its two ends still gives a palindrome).

1 and 2 are base cases and 3 is the general case.

Then we will have the following unoptimiezd DP code.

1     string longestPalindrome(string s) { 2         int start = 0, len = 1, n = s.length(); 3         bool dp[1000][1000] = {
false}; 4 for (int i = 0; i < n; i++) 5 dp[i][i] = true; 6 for (int i = 0; i < n - 1; i++) { 7 dp[i][i + 1] = s[i] == s[i + 1]; 8 if (dp[i][i + 1]) { 9 start = i;10 len = 2;11 }12 }13 for (int l = 3; l <= n; l++) {14 for (int i = 0; i < n - l + 1; i++) {15 int j = i + l - 1;16 dp[i][j] = dp[i + 1][j - 1] && s[i] == s[j];17 if (dp[i][j]) {18 start = i;19 len = l;20 }21 }22 }23 return s.substr(start, len);24 }

Note that each time when we update dp[i][j], we only need dp[i + 1][j - 1] from the left column, so we can maintain a single variable for it and reduce the space complexity from O(n^2) to O(n). The code now becomes as follows.

1     string longestPalindrome(string s) { 2         int start = 0, len = 1, n = s.length(); 3         bool cur[1000] = {
false}; 4 bool pre; 5 cur[0] = true; 6 for (int j = 1; j < n; j++) { 7 cur[j] = true; 8 pre = cur[j - 1]; 9 cur[j - 1] = s[j - 1] == s[j];10 if (cur[j - 1] && len < 2) {11 start = j - 1;12 len = 2;13 }14 for (int i = j - 2; i >= 0; i--) {15 bool temp = cur[i];16 cur[i] = pre && s[i] == s[j];17 if (cur[i] && j - i + 1 > len) {18 start = i;19 len = j - i + 1;20 }21 pre = temp;22 }23 }24 return s.substr(start, len);25 }

We may also traverse the string and expand to left and right from any character to obtain the longest palindrome. The following code should be self-explanatory.

1     string search(string s, int left, int right) { 2         int l = left, r = right; 3         while (l >= 0 && r < s.length() && s[l] == s[r]) { 4             l--; 5             r++; 6         } 7         return s.substr(l + 1, r - l - 1); 8     } 9     10     string longestPalindrome(string s) {11         string longest = s.substr(0, 1);12         for (int i = 0; i < s.length() - 1; i++) {13             string tmp1 = search(s, i, i);14             string tmp2 = search(s, i, i + 1);15             if (tmp1.length() > longest.length()) longest = tmp1;16             if (tmp2.length() > longest.length()) longest = tmp2;17         }18         return longest;19     }

Of course, this problem still has a non-trivial O(n) algorithm, named Manacher's algorithm. has a nice explanation for it. The final code is shown below.

1     string process(string s) { 2         int n = s.length(); 3         string t(2 * n + 3, '#'); 4         t[0] = '$'; 5         t[2 * n + 2] = '%'; 6         for (int i = 0; i < n; i++) 7             t[2 * (i + 1)] = s[i]; 8         return t; 9     }10     11     string longestPalindrome(string s) {12         string t = process(s);13         int n = t.length();14         int* plen = new int[n]();15         int center = 0, right = 0;16         for (int i = 1; i < n - 1; i++) {17             int i_mirror = 2 * center - i;18             plen[i] = right > i ? min(plen[i_mirror], right - i) : 0;19             while (t[i + plen[i] + 1] == t[i - plen[i] - 1])20                 plen[i]++;21             if (i + plen[i] > right) {22                 center = i;23                 right = i + plen[i];24             }25         }26         int maxlen = 0;27         for (int i = 1; i < n - 1; i++) {28             if (plen[i] > maxlen) {29                 center = i;30                 maxlen = plen[i];31             }32         }33         delete[] plen;34         return s.substr((center - 1 - maxlen) / 2, maxlen);35     }

转载于:https://www.cnblogs.com/jcliBlogger/p/4562069.html

你可能感兴趣的文章
重拾css(3)——学习css的思路
查看>>
SegmentFault 社区访谈 | 有位公子在奇舞
查看>>
jQuery源码分析之jQuery的定义
查看>>
一些经典面试题分析(上)
查看>>
[JS相关的记录01] 那什么来面对你,面向对象编程(__proto__,prototype,constructor以及原型链)...
查看>>
夏日葵电商:搭建一个商城系统,N+功能方案揭秘!
查看>>
Akka系列(一):Akka简介与Actor模型
查看>>
yii2获得从数据库获得数据的方法并处理
查看>>
Android开发百度地图(一)之初体验
查看>>
微服务指南走北(四):你不愿意做微服务架构的十个理由
查看>>
CSS代码重构与优化之路
查看>>
使用 sigprocmask 和 sigpending 在程序正文中捕获和处理信号
查看>>
Bodymovin插件的使用
查看>>
详细深入分析 Java ClassLoader 工作机制
查看>>
关于设计模式
查看>>
对一个“老”架构的重新思考
查看>>
DoubanFMPlayer, A mimic of Douban.fm player
查看>>
埃森哲、亚马逊和万事达卡抱团推出的区块链项目有何神通?
查看>>
2019年自动驾驶5大趋势预测:第一台Level 5 无人车问世
查看>>
后APP时代的破局之路 :阿里技术“三大容器五大方案”亮相,百川开放全面升级...
查看>>