代码改变世界

面试题6:字符串的包含

2016-03-21 20:47  Keiven_LY  阅读(444)  评论(0编辑  收藏  举报

题目描述

给定一长字符串a和一短字符串b,请问,如何最快判断出b中的所有字符是否都在a中?请编写函数bool StringCOntain(string &a, string &b)实现此功能。

举例:

  • 如果字符串a是”ABCD”,字符串b是”BAD”,则返回true,因为字符串b中的所有字符都在字符串a中,或者说b是a的子集。
  • 如果字符串a是”ABCD”,字符串b是”BCE”,则返回false,因为字符串b中的字符E不在字符串a中
  • 如果字符串a是”ABCD”,字符串b是”AA”,则返回true,因为字符串b中的字母A包含在字符串a中。

方法一:蛮力轮询

基本思想:轮询b中所有字符,逐个与字符串a中的每一个字符进行比较,看是否都在字符串a中。

bool StringContain(string &a, string &b)
{
    for(int i=0;i<b.length();i++)
    {
        for(int j=0;(j<a.length()) && (a[j] != b[i]);j++)
            ;
        if(j>=a.length())
        {
            return false;
        }
    }
    return true;
}

注解:如果字符串a的长度为m,字符串b的长度为n,则该算法的时间复杂度就是O(mn),显然,当m,n较大时,该算法的时间开销会很大。

方法二:素数相乘

基本思想:

首先,让字符串a中的每个字符对应一个素数,如A对应2,B对应3,C对应5,……以此类推。然后将a中的每个字符对应的素数相乘,得到一个整数。然后,让字符串b中的每一个字符也对应相应的素数,再用b中的每个字符对应的素数除上面得到的整数。如果有余数,说明结果为false,立即退出程序;如果整个过程中没有余数,则说明b是a的子集。

bool StringContain(string &a, string &b)
{
    const int p[26]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
                     59,61,67,71,73,79,83,89,97,101};
    int result=1;//存放字符串a每个字符对应素数的乘积
    for(int i=0; i<a.length(); i++)
    {
        int x = p[a[i] - 'A'];
        if(result % x)
        {
            result *= x;
        }
    }
    for(int i=0; i<b.length(); i++)
    {
        int x=p[b[i] - 'A'];
        if(resuilt % x)
            return false;
    }
    return true;
}

分析:算法的时间复杂度是O(m+n),最好情况下的时间复杂度是O(m),即在遍历b的第一个字符,就产生余数,便直接退出程序。

这种素数相乘看似可行,实则不行。因为素数相乘的结果可能会非常大,从而导致整数溢出。(前16个字母对应的素数相乘便会超出long long类型所能表示的最大整数范围)。