字符串包含

字符串包含

###题目描述 给定两个分别由字母组成的字符串A(长度为m)和字符串B(长度为n),字符串B的长度比字符串A短。请问,如何最快地判断字符串B中所有字母是否都在字符串A里?
为了简单起见,我们规定输入的字符串只包含大写英文字母,请实现函数bool StringContains(string &A, string &B)

比如,如果是下面两个字符串:
String 1:ABCD
String 2:BAD

答案是true,即String2里的字母在String1里也都有,或者说String2是String1的真子集。

如果是下面两个字符串:
String 1:ABCD
String 2:BCE

答案是false,因为字符串String2里的E字母不在字符串String1里。

同时,如果string1:ABCD,string 2:AA,同样返回true。


解法

轮询

对于字符串B中的每一个字母,是否能在字符串A中找到

显而易见时间复杂度为O(m*n)

改进分析:字符串A、B中可能存在重复字符,且遍历了字符串A之后,除了当前要找的字母外,其他字母其实也找过了,但是没有使用到这些信息。

先排序,后比较

按字母顺序排序后,按顺序线性扫描字符串A中的每一种字母,同时按顺序扫描字符串B中找是否有同样大小的字母。

先排序,快速排序时间复杂度分别为O(m log m)和(n log n),排好序后线性扫描分别需要O(m)和O(n)的时间

改进分析:排序后减少了无用的线性扫描,但题目只关心字母是否出现过,而不关心同种字母有多少个,所以排序过程中有多余的操作

计数排序

通过计数排序,可以得到每一种字母出现的次数。

先排序,时间复杂度分别为O(m)和(n),排好序后需要O(1)的时间(26个字母),辅助空间为长度为26的int数组2个,即 2642 bit

改进分析:题目只关心字母是否出现过,而不关心同种字母有多少个,可考虑用hashtable记录字母是否出现过即可。

标志位

将每个字母是否出现视作开关0 1,那么可以用26bit来表示26个字母是否出现过。

同理,但只需要2个长度为32bit的int32来表示,即 32*2 bit。对这两个int32做

改进分析:对字符串A每个字母进行位运算后得到hashA,不需要完全对字符串B每个字母进行位运算后得到hashB后再比较,而是当串B中的每个字母进行位运算时,就立即与hashA进行位与运算,结果为0则表示该字母在串A中不存在,立即返回false,节约了之后的计算。由此可得最小时间为O(m+1),最大时间为O(m+n)。

// “最好的方法”,时间复杂度O(n + m),空间复杂度O(1)
bool StringContain(string a, string b)
{
    int hash = 0;
    // 需要先将字符串A中的字母信息按位写入
    for (int i = 0; i < a.Length; ++i)
    {
        // 1左移n次,n为0~25 代表26个字母,如'C'-> 2, 则1左移2次,得到110(二进制表示)
        hash |= (1 << (a[i] - 'A'));
    }
    for (int i = 0; i < b.Length; ++i)
    {
        if ((hash & (1 << (b[i] - 'A'))) == 0)
        {
            return false;
        }
    }
    return true;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值