字符串的包含问题

字符串的包含

题目描述

​ 给定字符串str1与字符串str2,求解str1是否包含str2中所有元素。注意,这不是求子串。如:”ABCD”与”BCA”,返回结果true;”ABCD”与”AA”返回结果true;”ABCD”与”BCE”返回结果false。

解法一:蛮力轮询

​ 对于str2中每个元素,到str1中去遍历一遍,若无,则在str1中使用的索引应该会超过str1的边界。具体代码如下:

int string_contain(const char *str1, const char *str2)
{
    int len1 = (int) strlen(str1);
    int len2 = (int) strlen(str2);
    int i, j;
    for (i = 0; i < len2; ++i) {
        for (j = 0; j < len1 && str1[j] != str2[i]; ++j) {
            ;
        }

        if (j >= len1) {
            return false;
        }
    }

    return true;
}

​ 假设str1长度为m,str2长度为n,时间复杂度O(m * n)。

解法二:排序后轮询

​ 对于str1与str2,先进行排序处理,假设str1长度为m,str2长度为n,两者使用快速排序后,时间复杂度为O(m * logm) + O(n * logn),之后便是轮询,时间复杂度为O(m + n)。具体代码如下:

int string_contain(string &str1, string &str2)
{
    sort(str1.begin(), str1.end());
    sort(str2.begin(), str2.end());

    int i, j;
    for (i = 0; i < str2.length(); ++i) {
        for (j = 0; j < str1.length() && str1[j] < str2[i]; ++j) {
            ;
        }

        if (j >= str1.length() || str1[j] > str2[i]) {
            return false;
        }
    }

    return true;
}

​ 对于长度较长的字符串,解法二优于解法一,但如果数据大多都是长度较短的字符串,那解法一反而可能会比解法二好一些。

解法三:素数相乘

​ str1与str2中每个元素对应一个素数,如:’A’对应2,’B’对应3,’C’对应5,依次对应。str1中所有元素对应的素数相乘,str2中所有元素对应的素数相乘,两个结果求模,如果结果为0,则可判断str1中包含str2中的所有元素,反之不包含。具体代码如下:

int string_contain(const char *str1, const char *str2)
{
    int prime[] = {
        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 i;
    long long f = prime[(int) (str1[0] - 'A')];
    for (i = 1; i < strlen(str1); ++i) {
        int x = prime[(int) (str1[i] - 'A')];
        if (f % x) {
            f *= x;
        }
    }

    for (i = 0; i < strlen(str2); ++i) {
        int x = prime[(int) (str2[i] - 'A')];
        if (f % x) {
            return false;
        }
    }

    return true;
}

​ 这个解法对于字符串很短的情况可以解决,对于字符串长一点的情况就存在整数溢出的问题,严格来说,这不算一种正确的解法,前16个素数相乘就会产生溢出,所以仅能适用于一些情况。假设str1长度为m,str2长度为n,时间复杂度为O(m + n)。

解法四:位运算

​ 英文字符大小写都算有52个,仅算大写的话,只有26个,这样就可以使用一个32位大小的int,采用对1进行”<<”运算,再与该int做”&”运算的方式作为记录,根据该记录去判断是否包含相应的串了。具体代码如下:

int string_contain(const char *str1, const char *str2)
{
    int hash = 0;
    int i;
    for (i = 0; i < strlen(str1); ++i) {
        hash |= (1 << ((int) (str1[i] - 'A')));
    }

    for (i = 0; i < strlen(str2); ++i) {
        if ((hash & (1 << ((int) (str2[i] - 'A')))) == 0) {
            return false;
        }
    }

    return true;
}

​ 从代码上能够清晰看到思路,这里需要保证int至少有32位。空间复杂度为O(1),时间复杂度为O(m + n)。效率上是比较高的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值