1. 程式人生 > >22562 Problem A 【字串】最長迴文子串

22562 Problem A 【字串】最長迴文子串

問題 A: 【字串】最長迴文子串

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 114  解決: 56
[提交][狀態][討論版][命題人:外部匯入]

題目描述

        輸入一個字串,求出其中最長的迴文子串。子串的含義是:在原串中連續出現的字串片段。迴文的含義是:正著看和倒著看相同。如abba和yyxyy。在判斷迴文時,應該忽略所有標點符號和空格,且忽略大小寫,但輸出應保持原樣(在迴文串的首部和尾部不要輸出多餘字元)。

輸入字串長度不超過5000,且佔據單獨的一行。應該輸出最長的迴文串,如果有多個,輸出起始位置最靠左的。

輸入

一行字串,字串長度不超過5000。

輸出

字串中的最長迴文子串。

樣例輸入

Confuciuss say:Madam,I'm Adam.

樣例輸出

Madam,I'm Adam

提示

樣例說明:Madam,I'm Adam去掉空格、逗號、單引號、忽略大小寫為MADAMIMADAM,是迴文。
演算法分析一: 
首先解決“判斷時忽略標點,輸出進卻要按原樣”的問題? 可以用一個簡單的方法:預處理。構造一個新字串,不包含原來的標點符號,而且所有字元變成大寫(順便解決了大小寫的問題)。用到的函式: 
(1)isalpha(c)用來檢查c是否為字母,如果是字母,則返回1;否則返回0。
(2)isdigit(c)用來檢查c是否為數字(0~9),如果是數字,則返回1;否則返回0。
(3)toupper(c)用來將c字元轉換為大寫字母,返回c對應的大寫字母。
(4)tolower(c)用來將c字元轉換為小寫字母,返回c對應的小寫字母。
下面來列舉迴文串的起點和終點,然後判斷它是否真的是迴文串。
int max=0;
for(i = 0; i < m; i++)
   for(j = i; j < m; j++)
       if(s[i..j]是迴文串 && j-i+1 > max) max = j-i+1;
“當前最大值”變數max,它儲存的是目前為止發現的最長迴文子串的長度。如果串s的第i個字元到第j個字元(記為s[i..j])是迴文串,則檢查長度j-i+1是否超過max。
判斷s[i..j]是否為迴文串的方法如下:
int ok = 1;
for(k = i; k <= j; k++)
    if(s[k] != s[i+j-k])   ok = 0;
s[k]的“對稱”位置是s[i+j-k],因為只要一次比較失敗,就應把標記變數ok置為0。
最後的問題:原樣輸出。
    由於在求max值時,不知道s[i]和s[j]在原串buf中的位置。因此,必須增加一個數組p,用p[i]儲存s[i]在buf中的位置。在預處理得到,然後在更新max的同時把p[i]和p[j]儲存到x和y,最後輸出buf[x]到buf[y]中的所有字元。
不足:

當輸入字串較長時,容易超時,因列舉迴文起點和終點,迴圈過多。
演算法分析二:列舉迴文串的“中間”位置i,然後不斷往外擴充套件,直到有字元不同。提示:長度為奇數和偶數的處理方式是不一樣的。 

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<ctype.h>
using namespace std;
int main() {
	string s;
	while (getline(cin, s)) {
		int p[5000], len = 0, max = 0, x, y;
		//p儲存str在s中位置,len=str.length()
		//max=最長迴文子串長度,xy=迴文子串始末位置
		char str[5000];
		for (int i = 0; i < s.length(); i++) {
			if (isalpha(s[i])) {//去除標點空格等並轉為大寫字母儲存到str中
				str[len] = toupper(s[i]);
				p[len++] = i;//記錄相應位置
			}
		}
		//方法一:列舉迴文串從中間向外擴充套件:O(n平方)
		//奇數
		for (int i = 0; i < len; i++) {
			int num = 1, j;
			for (j = 1; i + j < len&&i - j>0; j++) {
				if (str[i + j] == str[i - j]) num += 2;
				else break;
			}
			if (num > max) {
				max = num;
				x = p[i - j + 1];
				y = p[i + j - 1];
			}
		}
		//偶數
		for (int i = 0; i < len - 1; i++) {
			int num = 0, j;
			for (j = 0; i + 1 + j < len&&i - j>0; j++) {
				if (str[i - j] == str[i + 1 + j]) num += 2;
				else break;
			}
			if (num > max) {
				max = num;
				x = p[i - j + 1];
				y = p[i + j];
			}
		}

/*方法二:從頭到尾暴力列舉(超時40%)
		for (int i = 0; i < len; i++) {
			for (int j = i; j < len; j++) {
				int ok = 1;
				for (int k = i; k <= (i + j) / 2; k++) {
					if (str[k] != str[i + j - k]) ok = 0;
				}
				if (ok&&j - i + 1 > max) {
					max = j - i + 1;
					x = p[i];
					y = p[j];
				}
			}
		}
*/
		for (int i = x; i <= y; i++) {
			cout << s[i];
		}
		cout << endl;
	}
	return 0;
}