A字符串>B字符串,问A字符是否包含字符串B的所有字符。是否包含子串问题同样适合。
例1,ABCDEFGHLMNOPQRS"是否包含"ODCGSRQPOMC"?
解法一:
(1)先让字符串有序。时间复杂度为o(nlogn);
(2)比较两个有序的字符串。时间复杂度为O(m+n);
比较两个有序字符串的通用算法:
用两层循环,外层循环是短的字符串,内层循环是长的字符串。
for(int i=0,j=0;i<t.length;i++){
//外层短字符串,
while(j<s.length&&t[i]>s[j]){
//内层长字符串,每次都是从当前j继续遍历,所以内层循环总共只循环了一轮。所以总共循环次数O(n*1)+O(m)
j++;
}
if (j>=s.length||t[i]<s[j]) {//这一步是提前停止循环
//j>=s.length表示只能找到全比t[i]小的s[j],例如s:ADEFG t:AHI
//s[j]>t[i]表示只能找到比t[i]大的s[j],因为是升序,所以找到一个这样的s[j],后面的都比t[i]大。例如s:ADEFG t:ABC
return false;
}
解法二:
使用散列表的思想。
(1)设散列表为装有26个素数的数组。
(2)将长字符串与散列表建立对应关系(通过p[s[i]-'A']),生成乘积
(3)短字符串与散列表建立关系,看短字符串是否是乘积的因子
空间复杂度26,时间复杂度O(m+n)
解法三:
使用散列表思想,这里的散列表利用位运算,可以将空间复杂度降低到O(1)
补充:位运算
(a)&:相同位的两个数字都为1,则为1;若有一个不为1,则为0
00101
11100
---------
00100
(b)|:相同位的两个数字都为0,则为0;若有一个不为0,则为1
00101
11100
----------------
11101
(1)利用位运算(或|)生成散列表,hash|=1<<s[i]-'A';
(2)利用位运算(与&)判断短字符串是否被包含在长字符hash&1<<t[j]-'A'
兄弟字符串即等长的字符串,相当于字符串包含问题的特殊情况。也可以用散列表。
例1GCDMOPQSR"和"DCGSRQPOM是否是兄弟字符串?
(1)生成长度为26的数组当做散列表。
(2)将字符串M与散列表建立对应关系hash[s[i]-'A']。并将每个字符出现的字符放入散列表中hash[s[i]-'A']++。
(3)将字符串N与散列表建立对应关系hash[t[j]-'A'],并将每个字符出现的字符放入散列表中hash[t[j]-'A']--