回文字符串



题目描述:

        回文字符串是指从左到右和从右到左相同的字符串,现给定一个仅由小写字母组成的字符串,你可以把它的字母重新排列,以形成不同的回文字符串。 输入:非空仅由小写字母组成的字符串,长度不超过100; 输出:能组成的所有回文串的个数(因为结果可能非常大,输出对1000000007取余数的结果)。 例如:输入"aabb" 输出为2(因为“aabb”对应的所有回文字符串有2个:abba和baab) 函数头部 c: int palindrome(const char *s); c++ int palindrome(const string &s); java public static int palindrome(String s) ;           

       分析:哎,这题最要命的就是大整数处理问题 ,算小弟能力有限,只能用java完成这道题 ,因为如果用C的话处理大整数确实麻烦,而对于这道题简直是更加的麻烦。我没有更好的方法去完成,所以只能用java大整数,暴力解决,不过要注意时间复杂度的问题,要不然会超时。代码有注释,请信息看。不过在这里想说下这题的思路。其实这是一道地地道道的排列题目,但是并不是边排列边计数,而是通过找递推式子或者找出其中的规律,现在就让我们来找规律吧。

1、s=“aabb”;回文数counts=2!/(1!*1!);  

2、s="aabbcc";回文数counts=3!/(1!*1!*1!);  

3、s="aabbccc";回文数counts=3!/(1!*1!*1!);  

4、s="aabbbbcc";回文数counts=4!/(1!*2!*1!);  

5、s="aabbbcccc";回文数counts=4!/(1!*1!*2!);  

.....

.....

.....

n、s;回文数counts=n/(c1!*c2!*......*c26!);

说明:n为字符串字符串s长度的一半,c1...26为字符串中某个字符个数的一半。它们的一般都是向下取整。

代码实现:

import java.math.BigInteger;
public class Main {
	public static int palindrome(String s)
	{
		int[] counts = new int[26];
		int i, j, k = 1, tk, p = 0, judge = 0, sum = 0, pp = 0, zero = 0, temp = 1;//声明一堆变量,judge判断字符串是否合法、sum为字符串总和、zero判断是否为单一字符,其他不解释了
		char ss[] = s.toCharArray();
		BigInteger allcounts = BigInteger.valueOf(1);
		BigInteger eps = BigInteger.valueOf(0);
		int len = s.length();
		for (i = 0; i < 26; i++) counts[i] = 0;
		for (i = 0; i < len; i++)//计算每种字符个数
		{
			counts[ss[i] - 'a']++;
		}
		for (i = 0; i < 26; i++)//判断字符串合法性
		{
			if (counts[i] % 2 == 1)
			{
				judge++;
			}
			if (counts[i] == 0)
			{
				zero++;
			}//计数折半
			counts[i] /= 2;
			sum += counts[i];
		}
		if (zero == 25)//单一字符
		{
			return 1;
		}
		if (judge >= 2)//字符串不合法
		{
			return 0;
		}
		for (i = 1; i <= sum; i++)//计算阶乘
		{
			temp *= i;
			if (temp >= 20000000 || i == sum)//这部很重要,减低时间复杂度
			{
				allcounts = allcounts.multiply(BigInteger.valueOf(temp));
				temp = 1;
			}
		}
		temp = 1;
		for (i = 0; i<26; i++)//重复字符数阶乘
		{
			for (j = 1; j <= counts[i]; j++)
			{
				temp *= j;
				if (temp >= 20000000 || j == counts[i])//这部很重要,减低时间复杂度
				{
					allcounts = allcounts.divide(BigInteger.valueOf(temp));//除去重复
					temp = 1;
				}
			}
		}

		eps = allcounts.divide(BigInteger.valueOf(1000000007));//计算有多少个10000000007
		allcounts = allcounts.add(eps.multiply(BigInteger.valueOf(-1000000007)));//对1000000007求余
		return allcounts.intValue();
	}


	//start 提示:自动阅卷起始唯一标识,请勿删除或增加。 
	public static void main(String args[])
	{
		System.out.println(palindrome("hqaymehhrsfuqrpahrimsxftuxqrpsejouuehaqtsryxjhearxmogmi"));
	}
	//end //提示:自动阅卷结束唯一标识,请勿删除或增加。

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值