回文串问题总结

回文串的问题很经典,也很常见,涉及到递归,循环,动态规划等方面,这里总结一下几种类型,供以后回顾,有问题请大家指正

1、回文串的判断   leetcode上的题目

bool isPalindrome(const char* src)
{
	if(src == NULL)return true;
	int end = strlen(src)-1,begin = 0;
	while(begin < end)//从两边向中间判断,当然也可以从中间向两边判断
	{
		if(src[begin] != src[end])return false;
		begin ++;
		end --;
	}
	return true;
}

2、最长回文子串  leetcode上的题目 用方法一会超时

方法一:动态规划

void LongestPalindromeDP(const char* src)//DP算法
{
	if(src == NULL)return;
	int length = strlen(src);
	bool dp[length][length];
	int i,j,len,maxLen = 1,begin = 0,end = 0;
	for(i = 0;i < length;i++)
	{
		memset(dp[i],false,sizeof(bool)*length);
	}
	for(len = 2;len <= length;len++)
	{
		for(i = 0;i + len - 1 < length;i++)
		{
			j = i+len-1;
			if(src[i] == src[j] && (j - i <= 2 || dp[i+1][j-1]))//dp[i][j]表示从第i到第j个元素是否为回文串
			{
				dp[i][j] = true;
				begin = i;
				end = j;
				maxLen = len;
			}
		}
	}
	for(i = begin;i <= end;i++)cout << src[i];
	cout << endl;
}

方法二:从中间向两边扩展

int expandAroundCenter(const char* src,int left,int right)//从中间往两头判断最长回文串
{
	int length = strlen(src);
	while(left >= 0 && right < length && src[left] == src[right])
	{
		left --;
		right ++;
	}
	return right - left - 1;
}
void LongestPalindromeCenter(const char* src)
{
	if(src == NULL)return;
	int length = strlen(src);
	int i,maxLen = 1,begin = 0,end = 0;
	for(i = 0;i < length;i++)
	{
		int len = expandAroundCenter(src,i,i);//针对奇数
		if(len > maxLen)
		{
			maxLen = len;
			begin = i - ((len-1) >> 1);
			end = i + ((len-1) >> 1);
		}
		len = expandAroundCenter(src,i,i+1);//针对偶数
		if(len > maxLen)
		{
			maxLen = len;
			begin = i - ((len-1) >> 1);
			end = i + 1 + ((len-1) >> 1);
		}
	}
	for(i = begin;i <= end;i++)cout<< src[i];
	cout << endl;
}

3、给一个串,问最少添加几个字符使得该串变成回文串

例如:abcd需要添加3个,变成abcdcba

int changeToPalindrome(const char* src)
{
	if(src == NULL)return 0;
	int length = strlen(src);
	int dp[length][length];
	int i,j,len;
	for(i = 0;i < length;i++)memset(dp[i],0,sizeof(int)*length);
	for(len = 2;len <= length;len++)
	{
		for(i = 0;i + len - 1 < length;i++)
		{
			j = i + len - 1;
			if(src[i] == src[j])dp[i][j] = dp[i+1][j-1];//dp[i][j]表示从第i个到第j个需要添加的字符数
			else dp[i][j] = 1 + min(dp[i+1][j],dp[i][j-1]);//在前面或者后面添加一个字符
		}
	}
	return dp[0][length-1];
}

4、回文数字,leetcode上的题目

bool isPalindrome(int x) {
	if(x < 0)return false;
	int base = 1;
	while(x / 10 >=base)base *= 10;//获取最高位的权值
	while(x > 0)
	{
		int left = x / base;//最高位
		int right = x % 10;//最低位
		if( left != right)return false;
		x -= base*left;
		x /= 10;//除去最高最低位
		base /= 100;
	}
	return true;
}

附,把一个数字reverse

int reverseNum(int num)
{
	int MAX = numeric_limits<int>::max();
	int MIN = numeric_limits<int>::min();
	int res = 0,flag = 1;
	if(num < 0)flag = -1;
	while(num != 0)
	{
		int low = num % 10;//商和余数的符合和被除数相同
		if(flag == 1 && (MAX / 10 < res || (MAX / 10 == res && low > MAX % 10)))//溢出测试不能用乘法,要用除法
		{
			cout << "over flow 1"<<endl;
			return -1;
		}
		else if(flag == -1 && (MIN / 10 > res || (MIN / 10 == res && low < MIN % 10)))
		{
			cout << "over flow 2" << endl;
			return -1;
		}
		res = (res * 10)+low;
		num /= 10;
	}
	return res;
}

5、回文串的最小分割数 leetcode上的题目

int minCut(string s) {
	int length = s.size();
	if(length <= 0)return 0;
	bool isParlindrome[length][length];
	int i,j;
	for(i = 0;i < length;i++)
	{
		memset(isParlindrome[i],false,sizeof(bool)*length;
	}
	int dp[length+1];
	for(i = length;i >= 0;i--)dp[i] = length - i - 1;
	for(i = length-1;i >= 0 ;i--)
	{
		for(j = i;j < length;j++)
		{
			if(s[i] == s[j] && (j - i <= 2 || isParlindrome[i+1][j-1]))
			{
				isParlindrome[i][j] = true;
				dp[i] = min(dp[i],1+dp[j+1]);
			}
		}
	}
	return dp[0];
}

6、所有的分割回文串  leetcode上的题目

bool isPalindrome(string s,set<string>& hash)
{
	set<string>::iterator iter = hash.find(s);
	if(iter != hash.end())return true;//如果该部分已经判断过,则直接返回
	int i = 0,j = s.size()-1;
	while(i < j)
	{
		if(s[i++] != s[j--])return false;
	}
	hash.insert(s);
	return true;
}
void dfs(string s,vector<vector<string> >& res,vector<string>& v,set<string>& hash)
{
	int length = s.size();
	if(length == 0)
	{
		res.push_back(v);
		return;
	}
	int i;
	for(i = 1;i <= length;i++)
	{
		string sub = s.substr(0,i);
		if(isPalindrome(sub,hash))//首先判断前半部分是不是回文串
		{
			v.push_back(sub);
			dfs(s.substr(i),res,v,hash);//递归调用后半部分
			v.pop_back();
		}
	}
}
vector<vector<string> > partition(string s) {
	int length = s.size();
	vector<vector<string> > res;
	vector<string> v;
	set<string> hash;
	if(length <= 0)return res;
	dfs(s,res,v,hash);//递归判断
	return res;
}

回文串问题总结

时间: 2024-08-02 13:51:15

回文串问题总结的相关文章

最少回文串--牛客网(秋招备战专场三模)-C++方向

题目描述:一个字符串从左向右和从右向左读都完全一样则是回文串,给定一个字符串,问该字符串中的字符所能组成的最少的回文串的个数为多少 解题思路:如果一个字符出现的次数为偶数,则必能组成回文串,如果一个字符出现奇数次,只能自己组成回文串,题目中问最少的回文串数目,即求出现次数为奇数次的字符个数即可,定义a存储每个字符出现的次数,统计出现奇数次的字符的个数,即为输出 1 #include <iostream> 2 #include <string> 3 using namespace s

回文串问题

1.回文串的判断 #include <iostream> #include <string.h> using namespace std; //回文串的判断 bool isPalindrome(const char* src) { if(src == NULL) return true; int end = strlen(src)-1,begin = 0; while(begin < end)//从两边向中间判断,当然也可以从中间向两边判断 { if(src[begin] !

bzoj 2565: 最长双回文串

Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同).输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串. Input 一行由小写英文字母组成的字符串S. Output 一行一个整数,表示最长双回文子串的长度. Sample Input baacaabbacabb Sample Output 12 HINT

BZOJ2565:最长双回文串

2565: 最长双回文串 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2195  Solved: 1119[Submit][Status][Discuss] Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同). 输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都

Power oj/2610[判断回文串]

题目链接[https://www.oj.swust.edu.cn/problem/show/2610] 题意:给你一个字符串,让你判断这个字符串是不是回文串,字符串的长度是1<len<1e7,内存是4096KB. 题解:首先这1e7个字符是存不下的,1e71024=9765KB>4096kB.那么怎么办?字符串哈希,先对字符串的前半部分进行哈希,然后在对字符串后半部分进行哈希,如果两部分的哈希值相同,那么这个字符串就是回文串. BKDRH哈希,哈希公式为has=has*seed+s[i]

409.求最长回文串的长度 LongestPalindrome

题目要求求出长度即可,并不需要求出最长回文串. 思路:用字典统计每一个字符的出现次数,出现次数大于1的字符必定出现在回文串中,另外还再加上一个中心点. public static int LongestPalindrome(string s) { int length = 0; Dictionary<char, int> dictionary = new Dictionary<char, int>(); int value = 0; foreach (char c in s) {

[haoi2009]求回文串

所谓回文串,就是对于给定的字符串,正着读和反着读都一样,比如ABCBA就是一个回文串,ABCAB则不是.我们的目标是对于任意输入的字符串,不断将第i个字符和第i+1个字符交换,使得该串最终变为回文串.求最少交换次数. 题解: 有一种做法是贪心: 就是每次找到最左端的字符,然后找到这序列中最右边的一样的字符,然后把这个字符移过去,然后把最左端右移,继续以上操作: 最后的答案就是每次的移动步数加起来: 要吐槽的是,window下I64d不要忘了...... #include<iostream> #

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串

Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,为逝查回文子串的最大出现值. Sample Input [样例输入l] abacaba [样例输入2] www Sample Output [样例输出l] 7 [样例输出2] 4 HINT 一个串是回文的,当且仅当它从左

LightOJ1258(线性回文串

题目:给出一个序列,求最少在后面加多少字符形成一个回文串. 思路:裸的manacher,注意枚举的起点和终点. /* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include &l

lintcode 容易题:Palindrome Partitioning 分割回文串

题目: 分割回文串 给定一个字符串s,将s分割成一些子串,使每个子串都是回文串. 返回s所有可能的回文串分割方案. 样例 给出 s = "aab",返回 [ ["aa","b"], ["a","a","b"] ] 解题: 这个题目不好搞啊,需要动态规划 在这里,没有根据动态规划,也解决了,貌似是暴力解决 从下标pos开始,找到下标i使得 pos到i内是回文字符串,再从i+1开始,找到下一