LeetCode第五題:最長迴文子串(C語言)
阿新 • • 發佈:2018-12-19
給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。
示例 1:
輸入: “babad” 輸出: “bab” 注意: "aba"也是一個有效答案。 示例 2:
輸入: “cbbd” 輸出: “bb”
解法一:暴力求解法
思想: 反轉 S,使之變成 S’。找到 S 和 S’之間最長的公共子串,這也必然是最長的迴文子串。 理由:如果找兩個字串的公共子串,i指向第一個字串,j指向第二個字串,用暴力求解法肯定就是i每走一步,j就不斷的從頭遍歷第二個字串,然後判斷是否相等。 j從前往後走,就相當於原字串從後向前走。 S=“abacdfgdcaba” , S ′ =“abacdgfdcaba”:S 以及 S’ 之間的最長公共子串為 “abacd”,顯然,這不是迴文。所以我們要加一個判斷條件就可以了。 暴力演算法的時間複雜度為O(n^3),在LeetCode中跑步過去,僅供參考
//判斷一個字串是不是迴文 int IfPlalindrome(char *s) { int count = strlen(s); int left = 0; int right = count - 1; while (left < right) { if (s[left] != s[right]) { return 0; //不是迴文返回0,是迴文返回1 } left++; right--; } return 1; } //反轉字串 char *reverse(char *s, int count) { char *p = (char *)malloc(sizeof(char) * (count + 1)); int i = 0; for (; i < count; i++) { p[i] = s[count - i - 1]; } p[i] = '\0'; return p; } char* longestPalindrome(char* s) { int count = strlen(s); //arr中存放的是最長的迴文子串 char *arr = (char *)malloc(sizeof(char) * 1001); char *p = reverse(s, count); unsigned int max = 0; //arr1中存放每一次迴圈遇見的迴文子串 char arr1[2000]; for (int i = 0; i < count; i++) { for (int j = 0; j < count; j++) { int m = i; int n = j; int k = 0; while (s[m] == p[n]) { arr1[k] = s[m]; k++; m++; n++; } arr1[k] = '\0'; //判斷是不是迴文子串 if (IfPlalindrome(arr1)) { //和arr中的迴文子串長度作對比,大的話,就更新 if (strlen(arr1) > max) { max = strlen(arr1); strcpy(arr, arr1); } } } } return arr; }
解法二:動態規劃
在暴力求解法中,判斷子串用了很多重複的操作,動態規劃就是要儘量避免重複的操作。 s的長度為N,生成一個N*N的二維陣列dp[1001][1001]
- dp[i][j] 表示從s[i]到s[j]是否是迴文
- dp[i][i] = true 因為dp[i][i]一定是迴文
- 在動態規劃中只需要記錄迴文開始的位置和長度即可 時間複雜度:O(n^2) 空間複雜度:O(N^2)
char* longestPalindrome(char* s) { int len = strlen(s); if (len <= 1) { return s; } //定義bool型別的dp,只能為true或false bool dp[1001][1001]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for (int i = 1; i < len; i++) { dp[i][i] = true; //一定不要忽略,在下面k=2會用到 dp[i][i - 1] = true; } int left = 0; int right = 0; int max = 0; //k表示迴文子串的長度 for (int k = 2; k <= len; k++) { //i表示迴文子串的起始位置 for (int i = 0; i < len - k + 1; i++) { if (s[i] == s[k - 1 + i] && dp[i + 1][k + i - 2]) { dp[i][k - 1 + i] = true; if (max < k - 1) { max = k - 1; left = i; right = k - 1 + i; } } } } char *arr = (char *)malloc(sizeof(int) * (max * 2)); int i = 0; for (; i <= max; i++) { arr[i] = s[left++]; } arr[i] = '\0'; return arr; }
解法三:中心擴充套件法
以某個元素為中心,分別計算偶數長度的迴文最大長度和奇數長度的迴文最大長度。 時間複雜度O(N^2)
char* longestPalindrome(char* s)
{
int len = strlen(s);
if (len <= 1) { return s; }
int start = 0;
int maxlen = 0;
//i表示中間元素下標
for (int i = 1; i < len; i++)
{
//偶數長度
int low = i - 1;
int high = i;
while (low >= 0 && high < len && s[low] == s[high])
{
low--;
high++;
}
if (high - low - 1 > maxlen)
{
maxlen = high - low - 1;
start = low + 1;
}
//奇數長度
low = i - 1; high = i + 1;
while (low >= 0 && high < len && s[low] == s[high])
{
low--;
high++;
}
if (high - low - 1 > maxlen)
{
maxlen = high - low - 1;
start = low + 1;
}
}
char *arr = (char *)malloc(sizeof(int) * (maxlen * 2));
int i = 0;
for (; i < maxlen; i++)
{
arr[i] = s[start++];
}
arr[i] = '\0';
return arr;
}