第四章作業-串-計算機17級 7-1 最長對稱子串 (25 分)四種方法求解(暴力列舉+動態規劃+中心擴充套件+manacher演算法(馬拉車))
7-1 最長對稱子串 (25 分)
對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?
,最長對稱子串為s PAT&TAP s
,於是你應該輸出11。
輸入格式:
輸入在一行中給出長度不超過1000的非空字串。
輸出格式:
在一行中輸出最長對稱子串的長度。
輸入樣例:
Is PAT&TAP symmetric?
輸出樣例:
11
方法一:直接暴力列舉
求每一個子串時間複雜度O(N^2), 判斷子串是不是迴文O(N),兩者是相乘關係,所以時間複雜度為O(N^3)。
演算法程式碼:
#include <iostream> using namespace std; string longestPalindrome(string &s) { int len = s.size(); //字串長度 int maxlen = 1; //最長迴文字串長度 int start = 0; //最長迴文字串起始地址 for(int i = 0; i < len; i++) //起始地址 { for(int j = i + 1; j < len; j++) //結束地址 { int tmp1 = i, tmp2 = j; while(tmp1 < tmp2 && s.at(tmp1) == s.at(tmp2))//判斷是不是迴文 { tmp1++; tmp2--; } if(tmp1 >= tmp2 && j - i + 1 > maxlen) { maxlen = j - i + 1; start = i; } } } return s.substr(start, maxlen); } int main() { string s; cout << "Input source string: "; cin >> s; cout << "The longest palindrome: " << longestPalindrome(s); return 0; }
此外補充一種非常好的方法:(強烈推薦)
分析:有兩種可能,一種是迴文字串的長度為奇數,一種是偶數的情況。i為字串當前字元的下標。
當迴文字串為奇數的時候,j表示i-j與i+j構成的迴文字串長度;當迴文字串長度為偶數的時候,j表示i+1左邊j個字元一直到i右邊j個字元的迴文字串長度~~~
用maxvalue儲存遍歷結果得到的最大值並且輸出~~
這種演算法思路非常清晰且易懂
#include <bits/stdc++.h> using namespace std; int main() { string ss; getline(cin,ss); int temp,maxvalue=0; int len = ss.size() for(int i = 0; i < len; i++) { temp = 1; ///迴文串為奇數 for(int j = 1; j < len; j++) { if(i - j < 0 || i + j >= len || s[i - j] != s[i + j]) break; temp += 2; } ///迴文串為偶數 maxvalue = temp > maxvalue ? temp : maxvalue; temp = 0; for(int j = 1; j < len; j++) { if(i - j + 1 < 0 || i + j >= len || s[i - j + 1] != s[i + j]) break; temp += 2; } maxvalue = temp > maxvalue ? temp : maxvalue; } cout << maxvalue; }
方法二:動態規劃
分析:有兩種可能,一種是迴文字串的長度為奇數,一種是偶數的情況。i為字串當前字元的下標。
當迴文字串為奇數的時候,j表示i-j與i+j構成的迴文字串長度;當迴文字串長度為偶數的時候,j表示i+1左邊j個字元一直到i右邊j個字元的迴文字串長度~~~
用maxvalue儲存遍歷結果得到的最大值並且輸出~~
這種演算法思路非常清晰且易懂,但時間複雜度較大。求每一個子串時間複雜度O(N^2), 判斷子串是不是迴文O(N),兩者是相乘關係,所以時間複雜度為O(N^3)。
#include <iostream> using namespace std; int main() { string s; getline(cin, s); int maxvalue = 0, temp; int len = s.length(); for(int i = 0; i < len; i++) { temp = 1; ///迴文串為奇數 for(int j = 1; j < len; j++) { if(i - j < 0 || i + j >= len || s[i - j] != s[i + j]) break; temp += 2; } ///迴文串為偶數 maxvalue = temp > maxvalue ? temp : maxvalue; temp = 0; for(int j = 1; j < len; j++) { if(i - j + 1 < 0 || i + j >= len || s[i - j + 1] != s[i + j]) break; temp += 2; } maxvalue = temp > maxvalue ? temp : maxvalue; } cout << maxvalue; return 0; }
方法二:動態規劃
下面介紹動態規劃的方法,使用動態規劃可以達到最優的 O(n2) 複雜度。
令 dp[i][j] 表示 S[i] 至 S[j] 所表示的子串是否是迴文子串,是則為 1,不是則為 0。這樣根據 S[i] 是否等於 S[j] ,可以把轉移情況分為兩類:
-
- 若 S[i] == S[j],那麼只要 S[i+1] 至 S[j-1] 是迴文子串,S[i] 至 S[j] 就是迴文子串;如果S[i+1] 至 S[j-1] 不是迴文子串,則 S[i] 至 S[j] 也不是迴文子串。
- 若 S[i] != S[j],那麼 S[i] 至 S[j] 一定不是迴文子串。
由此可以寫出狀態轉移方程:
dp[i][j]={dp[i+1][j−1],S[i]==S[j]0,S[i]!=S[j]dp[i][j]={dp[i+1][j−1],S[i]==S[j]0,S[i]!=S[j]
邊界:dp[i][i]=1,dp[i][i+1] = (S[i] == S[i+1]) ? 1 : 0。
根據遞推寫法從邊界出發的原理,注意到邊界表示的是長度為 1 和 2 的子串,且每次轉移時都對子串的長度減了 1,因此不妨考慮按子串的長度和子串的初始位置進行列舉,即第一遍將長度為 3 的子串的 dp 值全部求出,第二遍通過第一遍結果計算出長度為 4 的子串的 dp 值 ……
演算法時間複雜度為O(N ^ 2)。
/*
最長迴文子串
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define maxn 1010
char S[maxn];
int dp[maxn][maxn];
int main() {
gets(S); // 輸入整行字元
int len=strlen(S), ans=1; // ans 記錄最長迴文子串長度
int i, j, L;
// 邊界
for(i=0; i<len; ++i) {
dp[i][i] = 1;
if(i < len-1) {
if(S[i] == S[i+1]) {
dp[i][i+1] = 1;
ans = 2;
}
}
}
// 狀態轉移方程
for(L=3; L<=len; ++L) { // 列舉子串長度
for(i=0; i+L-1 < len; ++i) { // 列舉子串的起始節點
j = i+L-1; // 子串的右端結點
if(S[i]==S[j] && dp[i+1][j-1]==1) {
dp[i][j] = 1;
ans = L; // 更新最長迴文子串長度
}
}
}
printf("%d\n", ans); // 輸出
return 0;
}
方法三:中心擴充套件法
中心擴充套件就是把給定的字串的每一個字母當做中心,向兩邊擴充套件,這樣來找最長的子迴文串。演算法複雜度為O(N^2)。
需要考慮兩種情況:
長度為奇數的迴文串,比如a, aba, abcba
長度為偶數的迴文串,比如aa, abba
給出演算法程式碼,關於此題實現還沒來得及寫。
#include <iostream>
#include <cstring>
using namespace std;
string longestPalindrome(string &s)
{
const int len = s.size();
int maxlen = 1;
int start = 0;
for(int i = 0; i < len; i++)//求長度為奇數的迴文串
{
int j = i - 1, k = i + 1;
while(j >= 0 && k < len && s.at(j) == s.at(k))
{
if(k - j + 1 > maxlen)
{
maxlen = k - j + 1;
start = j;
}
j--;
k++;
}
}
for(int i = 0; i < len; i++)//求長度為偶數的迴文串
{
int j = i, k = i + 1;
while(j >= 0 && k < len && s.at(j) == s.at(k))
{
if(k - j + 1 > maxlen)
{
maxlen = k - j + 1;
start = j;
}
j--;
k++;
}
}
return s.substr(start, maxlen);
}
int main()
{
string s;
cout << "Input source string: ";
cin >> s;
cout << "The longest palindrome: " << longestPalindrome(s);
return 0;
}
作者:海天一樹X
連結:https://www.jianshu.com/p/c82cada7e5b0
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。
方法四:Manacher演算法 (馬拉車)
Manacher演算法的時間複雜度為O(N)
#include <bits/stdc++.h>
using namespace std;
const int maxn =1e6;
string str;
string s_new;
int len[maxn<<1];
int init(string st)
{
int len = st.size();
s_new='$';
//int j = 2;
// cout<<st;
for(int i =1; i <= 2*len; i+=2)
{
s_new += '#';
s_new += st[i/2];
}
s_new+='#';
s_new+='\0';
return 2*len+1;// 返回 s_new 的長度
}
int Manacher(string st,int len_)
{
int mx = 0,ans = 0,po =0;//mx即為當前計算迴文串最右邊字元的最大值
for(int i =1; i <= len_ ; i++)
{
if(mx>i)
len[i]=min(mx-i,len[2*po-i]);
else
len[i]=1;//如果i>=mx,要從頭開始匹配
while(st[i-len[i]]==st[i+len[i]])
len[i]++;
if(len[i]+i>mx)//若新計算的迴文串右端點位置大於mx,要更新po和mx的值
{
mx = len[i]+i;
po = i;
}
ans = max(ans,len[i]);//返回Len[i]中的最大值-1即為原串的最長迴文子串額長度
}
return ans - 1;
}
int main()
{
getline(cin,str);
int l = init(str);
cout<<Manacher(s_new,l)<<endl;
return 0;
}
相關推薦
第四章作業-串-計算機17級 7-1 最長對稱子串 (25 分)四種方法求解(暴力列舉+動態規劃+中心擴充套件+manacher演算法(馬拉車))
7-1 最長對稱子串 (25 分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串
資料結構與演算法隨筆之------最長迴文子串四種方法求解(暴力列舉+動態規劃+中心擴充套件+manacher演算法(馬拉車))
所謂迴文串,就是正著讀和倒著讀結果都一樣的迴文字串。 比如: a, aba, abccba都是迴文串, ab, abb, abca都不是迴文串。 一、暴力法 方法一:直接暴力列舉 求每一個子串時間複雜度O(N^2), 判斷子串是不是迴文O(N),兩者是相乘關係,所以時間
第五章作業-陣列-計算機17級(帶詳細解析)
解析在下面 解析: p2-1: 可以省略行,但不能省略列,因為總的元素個數已知,如果只知道行數,並無法確定第二維中每一維有多少元素.但如果知道列數,即已知第二維每一維有多少元素,則,
7-64 最長對稱子串 (25 分)
7-64 最長對稱子串 (25 分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你
7-8 最長對稱子串 (25 分)
7-8 最長對稱子串 (25 分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串。 輸出格式:
7-9 最長對稱子串(25 分)
對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串。 輸出格式: 在一行中輸出最長對稱子
中M2018春C入門和進階練習集-程式設計題64 7-64 最長對稱子串(25 分)
7-64 最長對稱子串(25 分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串
7-4 最長對稱子串(25 分)
7-4 最長對稱子串(25 分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串。
7-64 最長對稱子串(25 分)
題目: 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串。 輸出格式
(一道老坑爹的題)第三章棧作業題2-棧及其應用-計算機17級 7-1 表示式轉換 (25 分)
7-1 表示式轉換 (25 分) 算術表示式有字首表示法、中綴表示法和字尾表示法等形式。日常使用的算術表示式是採用中綴表示法,即二元運算子位於兩個運算數中間。請設計程式將中綴表示式轉換為字尾表示式。 輸入格式: 輸入在一行中給出不含空格的中綴表示式,可
第三章作業題3--佇列-計算機17級 7-1 銀行業務佇列簡單模擬 (25 分)
7-1 銀行業務佇列簡單模擬 (25 分) 設某銀行有A、B兩個業務視窗,且處理業務的速度不一樣,其中A視窗處理速度是B視窗的2倍 —— 即當A視窗每處理完2個顧客時,B視窗處理完1個顧客。給定到達銀行的顧客序列,請按業務完成的順序輸出顧客序列。假定不考慮顧客先後到達的時
第六章樹和二叉樹--樹和森林-計算機17級 7-1 樹的同構 (25 分)(答案超詳解)
7-1 樹的同構 (25 分) 給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因為我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。
第六章樹和二叉樹作業1—二叉樹--計算機17級 7-1 根據後序和中序遍歷輸出先序遍歷 (25 分)
7-1 根據後序和中序遍歷輸出先序遍歷 (25 分) 本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。 輸入格式: 第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空
樹的同構 (25 分)(答案超詳解)第六章樹和二叉樹--樹和森林-計算機17級 7-1
7-1 樹的同構 (25 分) 給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因為我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。 圖1
修理牧場 (25 分)第六章樹和二叉樹--Huffman樹-計算機17級 7-1
7-1 修理牧場 (25 分) 農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要N塊木頭,每塊木頭長度為整數Li個長度單位,於是他購買了一條很長的、能鋸成N塊的木頭,即該木頭的長度是Li的總和。 但是農夫自己沒有鋸子,請人鋸木的酬金跟這段木頭的長度成正比。為簡
根據後序和中序遍歷輸出先序遍歷 (25 分)第六章樹和二叉樹作業1—二叉樹--計算機17級 7-1
7-1 根據後序和中序遍歷輸出先序遍歷 (25 分) 本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。 輸入格式: 第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空格分隔
L2-008. 最長對稱子串(馬拉車演算法)
對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定”Is PAT&TAP symmetric?”,最長對稱子串為”s PAT&TAP s”,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串。 輸出格式:
7-7 最長對稱子串 (25 分)
對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串。 輸出格式: 在一行中輸出最長對稱子串的長度
L2-008. 最長對稱子串(最長迴文串)
題目意思 求最長迴文串。 解題思路 直接用Manacher演算法,秒過,下面就一標準模板 程式碼部分 #include<iostream> #include<st
演算法題(二):找出最長對稱子串
做法與找出兩個字串的最長公共子串相似。先得到字串的反轉,再利用求最長公共子串的方法來求最長對稱子串。 public static void fun1(String str1) { if(str1==null ||str1.length()==0) { retur