题目描述:
假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些。从算法是讲,什么方法能最快的查出所有小字符串里的字母在大字符串里都有?
比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPOM
答案是true,所有在string2里的字母string1也都有。
如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPOZ
答案是false,因为第二个字符串里的Z字母不在第一个字符串里。
方法一:O(n*m)的轮询方法
思路:针对第二个字符串string2中每一个字符,一一与第一个字符串string1中每个字符依次轮询比较,看它是否在第一个字符串string1中。
实现代码:
int CompareSting(string LongSting,string ShortSting)
{
for (int i=0; i<ShortString.length(); i++)
{
for (int j=0; j<LongString.length(); j++) //O(n*m)
{
if (LongString[i] == ShortString[j]) //一一比较
{
break;
}
}
if (j==LongString.length())
{
cout << "false" << endl;
return 0;
}
}
cout << "true" << endl;
return 1;
}
方法二:O(mlogm)+O(nlogn)+O(m+n)的排序方法
思路:先对两个字符串string1和string2快速排序,然后然后同时对两个字串依次轮询。
int partition(string &str,int lo,int hi)
{
int key = str[hi]; //以最后一个元素,data[hi]为主元
int i = lo - 1;
for(int j = lo; j < hi; j++) ///注,j从p指向的是r-1,不是r。
{
if(str[j] <= key)
{
i++;
swap(str[i], str[j]);
}
}
swap(str[i+1], str[hi]); //不能改为swap(&data[i+1],&key)
return i + 1;
}
//递归调用上述partition过程,完成排序。
void quicksort(string &str, int lo, int hi)
{
if (lo < hi)
{
int k = partition(str, lo, hi);
quicksort(str, lo, k - 1);
quicksort(str, k + 1, hi);
}
}
//比较,上述排序O(m log m) + O(n log n),加上下面的O(m+n),
//时间复杂度总计为:O(mlogm)+O(nlogn)+O(m+n)。
void compare(string str1,string str2)
{
int posOne = 0;
int posTwo = 0;
while (posTwo < str2.length() && posOne < str1.length())
{
while (str1[posOne] < str2[posTwo] && posOne < str1.length() - 1)
posOne++;
//如果和str2相等,那就不能动。只有比str2小,才能动。
if (str1[posOne] != str2[posTwo])
break;
//posOne++;
//归并的时候,str1[str1Pos] == str[str2Pos]的时候,只能str2Pos++,str1Pos不可以自增。
//多谢helloword指正。
posTwo++;
}
if (posTwo == str2.length())
cout << "true" << endl;
else
cout << "false" << endl;
}
方法三:O(n+m)的hashtable的方法
思路:1、hash[26],先全部清零,然后扫描短的字符串,若有相应的置1;2、 计算hash[26]中1的个数,记为m ;3、扫描长字符串的每个字符a;若原来hash[a] == 1 ,则修改hash[a] = 0,并将m减1;若hash[a] == 0,则不做处理 ; 4、若m == 0 or 扫描结束,退出循环。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1="ABCDEFGHLMNOPQRS";
string str2="DCGSRQPOM";
// 开辟一个辅助数组并清零
int hash[26] = {0};
// num为辅助数组中元素个数
int num = 0;
// 扫描短字符串
for (int j = 0; j < str2.length(); j++)
{
// 将字符转换成对应辅助数组中的索引
int index = str1[j] - 'A';
// 如果辅助数组中该索引对应元素为0,则置1,且num++;
if (hash[index] == 0)
{
hash[index] = 1;
num++;
}
}
// 扫描长字符串
for (int k = 0; k < str1.length(); k++)
{
int index = str1[k] - 'A';
// 如果辅助数组中该索引对应元素为1,则num--;为零的话,不作处理(不写语句)。
if(hash[index] ==1)
{
hash[index] = 0;
num--;
if(num == 0) //m==0,即退出循环。
break;
}
}
// num为0说明长字符串包含短字符串内所有字符
if (num == 0)
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
方法四:O(n)到O(n+m)的素数方法
思路:1.定义最小的26个素数分别与字符'A'到'Z'对应。
2.遍历长字符串,求得每个字符对应素数的乘积。
3.遍历短字符串,判断乘积能否被短字符串中的字符对应的素数整除。
4.输出结果。
2.遍历长字符串,求得每个字符对应素数的乘积。
3.遍历短字符串,判断乘积能否被短字符串中的字符对应的素数整除。
4.输出结果。
实现:
#include <iostream>
#include <string>
#include "BigInt.h"
using namespace std;
// 素数数组
int primeNumber[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 main()
{
string strOne = "ABCDEFGHLMNOPQRS";
string strTwo = "DCGSRQPOM";
// 这里需要用到大整数
CBigInt product = 1; //大整数除法的代码,下头给出。
// 遍历长字符串,得到每个字符对应素数的乘积
for (int i = 0; i < strOne.length(); i++)
{
int index = strOne[i] - 'A';
product = product * primeNumber[index];
}
// 遍历短字符串
for (int j = 0; j < strTwo.length(); j++)
{
int index = strTwo[j] - 'A';
// 如果余数不为0,说明不包括短字串中的字符,跳出循环
if (product % primeNumber[index] != 0)
break;
}
// 如果积能整除短字符串中所有字符则输出"true",否则输出"false"。
if (strTwo.length() == j)
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
字符串匹配问题
题目描述:
假设两个字符串中所含有的字符和个数都相同我们就叫这两个字符串匹配,比如:abcda和adabc,
由于出现的字符个数都是相同,只是顺序不同,所以这两个字符串是匹配的。
要求高效实现下面的函数: boolen Is_Match(char *str1,char *str2)。
思路:HashTable方法。
在字符串中查找子串
相当于实现 strstr函数。可参考KMP
字符串转换为整数
注意:
1、由于整数可能不仅仅之含有数字,还有可能以'+'或者'-'开头,表示整数的正负。如果第一个字符是'+'号,则不需要做任何操作;如果第一个字符是'-'号,则表明这个整数是个负数,在最后的时候我们要把得到的数值变成负数。
2、如果使用的是指针的话,在使用指针之前,我们要做的第一件是判断这个指针是不是为空。如果试着去访问空指针,将不可避免地导致程序崩溃(此第2点在下面的程序不需注意,因为没有用到指针)。
3、输入的字符串中可能含有不是数字的字符。
每当碰到这些非法的字符,我们就没有必要再继续转换。
4、溢出问题。由于输入的数字是以字符串的形式输入,因此有可能输入一个很大的数字转换之后会超过能够表示的最大的整数而溢出。
1、由于整数可能不仅仅之含有数字,还有可能以'+'或者'-'开头,表示整数的正负。如果第一个字符是'+'号,则不需要做任何操作;如果第一个字符是'-'号,则表明这个整数是个负数,在最后的时候我们要把得到的数值变成负数。
2、如果使用的是指针的话,在使用指针之前,我们要做的第一件是判断这个指针是不是为空。如果试着去访问空指针,将不可避免地导致程序崩溃(此第2点在下面的程序不需注意,因为没有用到指针)。
3、输入的字符串中可能含有不是数字的字符。
每当碰到这些非法的字符,我们就没有必要再继续转换。
4、溢出问题。由于输入的数字是以字符串的形式输入,因此有可能输入一个很大的数字转换之后会超过能够表示的最大的整数而溢出。
字符串拷贝
- //10分
- //为了实现链式操作,将目的地址返回,加3分!
- char * strcpy( char *strDest, const char *strSrc )
- {
- assert( (strDest != NULL) && (strSrc != NULL) );
- char *address = strDest;
- while( (*strDest++ = * strSrc++) != '/0' );
- return address;
- }