深圳网站建设哪个平台好,网站推广公司排行榜,`北京网站建设,广西钦州网站建设1.2 字符串的包含题目描述给定一长字符串a和一短字符串b。请问#xff0c;如何最快地判断出短字符串b中的所有字符是否都在长字符串a中#xff1f;请编写函数bool StringContain(string a, string b)实现此功能。为简单起见#xff0c;假设输入的字符串只包含大写…1.2 字符串的包含题目描述给定一长字符串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中最直观也是最简单的思路则是轮询短字符串b中的每一个字符逐个与长字符串a中的每个字符进行比较看是否都在字符串a中。参考代码如下bool StringContain(string a, string b)
{for (int i 0; i b.length(); i){int j;for (j 0; (j a.length()) (a[j] ! b[i]); j);if (j a.length()){return false;}}return true;
}
如果n是长字符串a的长度m是短字符串b的长度那么此算法需要O(nm)次比较。显然如果n和m很大时间开销太大需要寻找更好的办法。解法二排序后轮询如果允许排序可以考虑先排序后轮询。例如可先对这两个字符串中的字母进行排序然后再对两个字符串依次轮询。常规情况下两个字符串的排序需要O(mlogm)O(nlogn)次操作之后的线性扫描需要O(mn)次操作。关于排序方法可以采用最常用的快速排序。参考代码如下bool StringContain(string a, string b)
{sort(a.begin(), a.end());sort(b.begin(), b.end());for (int pa 0, pb 0; pb b.length();){while ((pa a.length()) (a[pa] b[pb])){pa;}if ((pa a.length()) || (a[pa] b[pb])){return false;}pb;}return true;
}
解法三素数相乘有没有比排序后轮询更好的方法呢首先让长字符串a中的每个字母与一个素数对应如A对应2B对应3C对应5……依次类推。再遍历长字符串a把a中的每个字母对应的素数相乘得到一个整数。然后让短字符串b中的字母也对应相应的素数再用b中的每个字母对应的素数除上面得到的整数。如果结果有余数说明结果为false当即退出程序如果整个过程中没有余数则说明短字符串b是长字符串a的子集。具体思路总结如下。1按照从小到大的顺序用26个素数分别代替长字符串a中的所有字母。2遍历长字符串a求得a中的所有字母对应的素数的乘积。3遍历短字符串b判断上一步得到的乘积能否被b中的字母对应的素数整除。4输出结果。上述算法的时间复杂度为O(mn)。当然最好情况下的时间复杂度为O(n)即在遍历短字符串b的第一个字母与长字符串a中所有字符所对应的素数的乘积相除时当即出现余数便直接退出程序返回false。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 f 1;for (int i 0; i a.length(); i){int x p[a[i] - A];if (f % x){f * x;}}for (int i 0; i b.length(); i){int x p[b[i] - A];if (f % x){return false;}}return true;
}
这种素数相乘的方法看似可行实则不可行因为素数相乘的结果会很大从而导致整数溢出前16个字母对应的素数相乘便会超出long long类型所能表示的最大整数范围。解法四位运算法如果面试官继续追问到底有没有更好的办法呢或许你绞尽脑汁能想到计数排序。但除了计数排序还有别的办法吗事实上可以先把长字符串a中的所有字符都放入一个散列表hash table中然后轮询短字符串b看b中的每个字符是否都在散列表里如果都在说明长字符串a包含短字符串b否则说明不包含。再进一步可以用位运算26位整数表示为长字符串a计算出一个“签名”再逐一将短字符串b中的字符放到a中进行查找。参考代码如下bool StringContain(string a, string b)
{int hash 0;for (int i 0; i a.length(); i){hash | (1 (a[i] - A));}for (int i 0; i b.length(); i){if ((hash (1 (b[i] - A))) 0){return false;}}return true;
}
这个位运算方法的实质是用一个整数代替了散列表它的空间复杂度为O(1)时间复杂度为O(nm)。至此算是比较完美地解决了这个字符串包含的问题。但是这样真的完美了吗请读者继续思考。举一反三变位词如果两个字符串中的字符一样出现次数也一样只是出现的顺序不一样则认为这两个字符串是兄弟字符串。例如bad和adb即为兄弟字符串。现提供一个字符串请问如何在字典中迅速找到它的兄弟字符串END资料分享工作一到五年的程序员朋友面对目前的技术无从下手感到很迷茫高清思维导图及相关视频资料获取方式关注转发私信【架构】里面有阿里Java高级大牛直播讲解知识点分享知识课程内容都是各位老师多年工作经验的梳理和总结带着大家全面、科学地建立自己的技术体系和技术认知精讲直播课全面知识点分析丰富资料