生活随笔
收集整理的這篇文章主要介紹了
最长回文子串-三种DP实现
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
最長(zhǎng)回文子串
https://leetcode-cn.com/problems/longest-palindromic-substring/
給定一個(gè)字符串 s,找到 s 中最長(zhǎng)的回文子串。你可以假設(shè) s 的最大長(zhǎng)度為 1000。
示例 1:
輸入
: "babad"
輸出
: "bab"
注意
: "aba" 也是一個(gè)有效答案。
示例 2:
輸入
: "cbbd"
輸出
: "bb"
用動(dòng)態(tài)規(guī)劃來做,列舉了三種解法
文章目錄
解法一
-
動(dòng)態(tài)規(guī)劃求解:
- map[i][j]中,i表示起點(diǎn)坐標(biāo),j表示長(zhǎng)度
- map[i][1] = 1,單個(gè)的字符同樣為回文串
- 當(dāng)s[i] == s[i+1]時(shí)候, map[i][2] = 2,連續(xù)的串同樣為回文串
- map[i-1][j+2] = j+2 當(dāng)且僅當(dāng),map[i][j]非零(即對(duì)應(yīng)的字符串為回文串),且s[i-1] == s[i+j](即,兩邊同時(shí)擴(kuò)充一個(gè)位置),所以長(zhǎng)度就是其本身
-
T: 156 ms M: 14.8 MB
class Solution
{
public
:string
longestPalindrome(string s
) {if (s
.size() < 2)return s
;int map
[2000][2001];int total
= 1, start
=0;for (int i
= 0; i
< s
.size(); ++i
) map
[i
][1] = 1;for (int i
= 0; i
< s
.size()-1; ++i
){if (s
[i
] == s
[i
+1]) {map
[i
][2] = 2;total
= 2;start
= i
;}else {map
[i
][2] = 0;}}for (int j
= 3; j
<= s
.size(); ++j
){for (int i
= 0;i
<= s
.size() - j
; ++i
){if (map
[i
+1][j
-2] != 0 && s
[i
] == s
[i
+j
-1]) {map
[i
][j
] = j
;if (total
< map
[i
][j
]){total
= map
[i
][j
];start
= i
;}} else map
[i
][j
] = 0;}}return s
.substr(start
, total
);}
};
解法二
在解法一的基礎(chǔ)上做了改進(jìn),目的是降低空間需求。
其實(shí)很明顯,奇數(shù)長(zhǎng)度的回文串和偶數(shù)長(zhǎng)度的回文串之間是沒有直接關(guān)聯(lián)的。也就是,已知回文串,兩邊同時(shí)擴(kuò)張一個(gè)位置才可能有依據(jù)判斷是否為回文串。這樣的性質(zhì)將回文串明顯的分為奇偶兩種可能。
- 用取余的方式判斷奇偶,就將原來的1000 * 1001的空間要求縮短到了 1000 * 2
class Solution
{
public
:string
longestPalindrome(string s
) {if (s
.size() < 2)return s
;int map
[1000][2];int total
= 1, start
=0;for (int i
= 0; i
< s
.size(); ++i
) map
[i
][1] = 1;for (int i
= 0; i
< s
.size()-1; ++i
){if (s
[i
] == s
[i
+1]) {map
[i
][2 % 2] = 2;total
= 2;start
= i
;}else {map
[i
][2 % 2] = 0;}}for (int j
= 3; j
<= s
.size(); ++j
){for (int i
= 0;i
<= s
.size() - j
; ++i
){if (map
[i
+1][(j
-2) % 2] != 0 && s
[i
] == s
[i
+j
-1]) {map
[i
][j
%2] = j
;if (total
< map
[i
][j
% 2]){total
= map
[i
][j
% 2];start
= i
;}} else map
[i
][j
%2] = 0;}}return s
.substr(start
, total
);}
};
解法三
將解法二再改進(jìn)為只需要一維的數(shù)組。
明顯,我們可以先做偶數(shù)長(zhǎng)度的計(jì)算,之后,再算奇數(shù)的時(shí)候,只需要把原來的非0部分或者是更大的部分覆蓋掉就好了。
此外,這里還使用動(dòng)態(tài)分配內(nèi)存的方式。由于每次調(diào)用該函數(shù)時(shí)都不需要分配這么多的內(nèi)存,需要的時(shí)間就會(huì)更短。
但同時(shí)對(duì)于動(dòng)態(tài)分配內(nèi)存,對(duì)于內(nèi)存的存儲(chǔ)和釋放會(huì)需要更多的空間,因此空間上反而沒有更緩和。
class Solution
{
public
:string
longestPalindrome(string s
) {if (s
.size() < 2)return s
;int *map
;map
= new
int[s
.size()+1];int total
= 1, start
=0;for (int i
= 0; i
< s
.size()-1; ++i
){if (s
[i
] == s
[i
+1]) {map
[i
] = 2;total
= 2;start
= i
;}else {map
[i
] = 0;}}for (int j
= 4; j
<= s
.size(); j
+=2){for (int i
= 0;i
<= s
.size() - j
; ++i
){if (map
[i
+1] != 0 && s
[i
] == s
[i
+j
-1]) {map
[i
] = j
;if (total
< map
[i
]){total
= map
[i
];start
= i
;}} else map
[i
] = 0;}}for (int i
= 0; i
< s
.size(); ++i
) if (!map
[i
]) map
[i
] = 1;for (int j
= 3; j
<= s
.size(); j
+=2){for (int i
= 0;i
<= s
.size() - j
; ++i
){if (map
[i
+1] != 0 && s
[i
] == s
[i
+j
-1]) {map
[i
] = j
;if (total
< map
[i
]){total
= map
[i
];start
= i
;}} else map
[i
] = 0;}}delete
[]map
;return s
.substr(start
, total
);}
};
總結(jié)
以上是生活随笔為你收集整理的最长回文子串-三种DP实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。