庞果网---回文字符串

来源:互联网 发布:连接网络将服务器 编辑:程序博客网 时间:2024/04/28 19:35

题目:

回文字符串是指从左到右和从右到左相同的字符串,现给定一个仅由小写字母组成的字符串,你可以把它的字母重新排列,以形成不同的回文字符串。

 

输入:非空仅由小写字母组成的字符串,长度不超过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) ;

 

分析:

         该题目意图是给定一组字符,让你调整顺序构成回文字符串,统计回文字符串的数量。

观察回文字符串构成,可以确定:

a.      每个字符数量为偶数,可以构造出回文字符串,此时回文字符串的长度为偶数。比如题目给出的例子;

b.      仅有一个数量为奇数的字符,可以构造出回文字符串,此时回文字符串的长度为奇数。比如aab,可以构造出aba;

c.      有多个数量为奇数的字符时,不能构成回文字符串,比如,ab就无法构成回文字符串。

 

长度为偶数的回文字符串(长度为奇数时也一样分析,只要将奇数的那个字母去掉,因为此字母只能在对称点上):

将长度为偶数的回文字符串从中间切开,则每一侧的字符串长度为原来的一半,而且每个字符的数量也为原来的一半。比如aabb可以构成回文字符串abba,切开之后,每一侧为ab,含有原来一半的字符。

假设调整左半侧字符数按需,右侧也相应改变,那么将半侧的字符串求出全排列,则既可以得出所有回文字符串的数量。为了好理解,我再举个例子:

原始串:aaaabbcc,可以看出每个字符为偶数个,用|表示分割线,则所有的回文字符串为:

         aabc|cbaa                abac|caba        abca|acba

         aacb|bcaa                 acab|baca        acba|abca

         baac|caab                 baca|acab

         bcaa|aacb                

         cbaa|aabc                 caba|abac

         caab|baac                

一共有12种,为(4!/2!),即半侧字符串的全排列。

 

由上可知,问题转化为:

1. {Ai | 0<i<=n,n为字符种类数目};

2. Ai中奇数超过1个时返回0;

3. sum += Ai/2, M *= Ai!;

4. N = sum!;

5. N/M

 

在处理第3,4步时,采用分解质因数方法求中间结果,否则会出现溢出。

#include <map>#include <iostream>using namespace std;const int MOD = 1000000007;//通过分解质因数,统计每个质数的个数并保存在map中,根据分子还是分母情况在map中做加或减操作void primeAddStep(int n,map<int,int>& prime,int step){    while(n){        int tmp = n;        for (int i=2;i<=tmp;i++){            while((tmp>=i) && (0 == tmp%i)){                prime[i] += step;                tmp=tmp/i;            }        }        --n;    }}int palindrome(const string &s) {    //保存每个字符数目    map<char,int> charCount;    //分解质因数用    map<int,int> primeCount;    map<char,int>::iterator iter_charCount;    map<int,int>::iterator iter_primeCount;    int sum = 0;    int flag  = 0;    __int64 res = 1;    //统计每个字符的个数    for(string::size_type i=0;i<s.size();++i){        iter_charCount=charCount.find(s[i]);        if(iter_charCount != charCount.end())            ++iter_charCount->second;        else            charCount.insert(pair<char,int>(s[i],1));    }    for(iter_charCount=charCount.begin();iter_charCount!=charCount.end();++iter_charCount){        //判断字符数目是否为奇数,若奇数超过1个直接返回0        if(iter_charCount->second&0x01){            if(0==flag) ++flag;            else return 0;        }        //将字符数目减半        iter_charCount->second >> 1;        //累加减半后的字符数目        sum += iter_charCount->second;        //采用分解质因数方法,计算减半后的字符数目的阶乘的积        primeAddStep(iter_charCount->second,primeCount,-1);    }    //采用分解质因数方法,计算累计和的阶乘/字符数目阶乘积    primeAddStep(sum,primeCount,1);    //根据约分之后的结果,计算出最终数量    for(iter_primeCount=primeCount.begin();iter_primeCount!=primeCount.end();++iter_primeCount){        for(int i=0;i<iter_primeCount->second;++i){            res = (res*iter_primeCount->first)%MOD;        }    }    return int(res);}

最后感谢庞果网的各位网友的激情讨论


原创粉丝点击