文章目录
一. 推荐专栏
推荐算法专栏
《算法零基础100讲》(第22讲) 字符串算法(二) - 字符串比较
二. 重点知识
2.1 strcmp函数
strcmp是一个比较两个字符串的函数,从第一个字符开始,逐个比较(按照ASCLL码值),直到出现不同的字符或者出现’\0’。
头文件
#include <string.h>
函数定义
int strcmp(const char* str1, const char* str2);
返回值
- 如果str1小于str2,返回值 < 0;
- 如果str1大于str2,返回值 > 0;
- 如果str1等于str2,返回值 = 0;
2.2 strstr函数
strstr的作用是找到子串在一个字符串中第一次出现的位置。
头文件
#include <string.h>
函数定义
char* strstr(const char* str1, const* str2);
其中str1为被查找的字符串,str2为查找的字串
返回值
如果在str1中找到str2,将其第一次出现的地址返回,否则返回NULL。
三. 课后习题
3.1 替换空格
题目链接
剑指 Offer 05. 替换空格
思路分析:
我们只需要在遇到空格位置是分别将’%’,‘2’,'0’三个字符加入即可。
此外我们还需注意新字符串的长度,最后的情况是原来的三倍。
代码如下:
#define MAX 20000
char* replaceSpace(char* s){
char* ret = malloc(MAX);
int retSize = 0;
int len = strlen(s);
for(int i = 0; i < len; i++){
if(s[i] == ' '){
ret[retSize++] = '%';
ret[retSize++] = '2';
ret[retSize++] = '0';
}
else{
ret[retSize++] = s[i];
}
}
ret[retSize] = '\0';
return ret;
}
3.2 稀疏数组搜索
题目链接
面试题 10.05. 稀疏数组搜索
思路分析:
这道题其实很简单,我们只需要将word里面的每个字符串逐一与s进行比较即可,遇到相同的则返回其下表位置,没有则返回-1。
代码如下:
int findString(char** words, int wordsSize, char* s){
for(int i = 0; i < wordsSize; i++){
//如果是空格则直接跳过
if(words[i] == " "){
i++;
}
//比较是否相等
if(strcmp(words[i], s)== 0){
return i;
}
}
return -1;
}
3.3 单词规律
题目链接:
290. 单词规律
思路分析:
这道题用C写确实有写难受。
- 首先我的想法是用两个数组hash1,hash2分别记录pattern和s的规律,例如pattern:abba,则hash1:[0,1,1,0],后面出现相同的字符,则将其改为第一次出现的位置的下标,对于s也是如此记录。
- 然后问题来了,pattern很好记录,但s是比较一个一维符串数组里的单词,每个单词使用空格个开,它该如何比较每个单词呢?
- 这是我们需要定义一个指针数组hash,因为s用空格分开了每个单词,所以我们把所有空格改为’\0’,并且将每个单词的首个字符的地址放入hash中,这样单词就被分开了,如何使用strcmp进行比较,最后得到1中的想法,也就是hash2
代码如下:
bool wordPattern(char * pattern, char * s){
int len1 = strlen(pattern);
int len2 = strlen(s);
int hash1[len1];
int hash2[len1];
//初始化
for(int i = 0; i < len1; i++){
hash1[i] = i;
hash2[i] = i;
}
//将pattern的模式记录下来
for(int i = 0; i < len1 - 1; i++){
for(int j = i + 1; j < len1; j++){
if(pattern[i] == pattern[j]){
hash1[j] = hash1[i];
}
}
}
char* hash[256];
int hashSize = 0;
int flag = 1;
//将s中的单词拆分开来,并用指针数组hash存储
for(int i = 0; i < len2; i++){
if(flag){
hash[hashSize++] = s + i;
flag = 0;
}
if(s[i] == ' '){
s[i] = '\0';
flag = 1;
}
}
//特殊情况
if(len1 != hashSize){
return false;
}
//记录s的模式
for(int i = 0; i < hashSize - 1; i++){
for(int j = i + 1; j < hashSize; j++){
if(!strcmp(hash[i], hash[j])){
hash2[j] = hash2[i];
}
}
}
//比较hash1和hash2是否相同
for(int i = 0; i < len1; i++){
if(hash1[i] != hash2[i]){
return false;
}
}
return true;;
}
3.4 解码字母到整数映射
题目链接:
1309. 解码字母到整数映射
思路分析:
这题的主要难点就是 ‘#’ 这个符号,阻挠着我们,但问题也不大。
- 首先我们可以发现 j 之后的字符都是由三个字符表示,并且第三个字符是 ‘#’
- 然后我们可以根据这个规律,对每个字符后面第二个字符进行判断。
- 如果是带 ‘#’ 这个字符的话,他们都是由两个字符对应,这使我们难以通过ASCLL码值进行计算,所以我们要用以个简短的字符串保存它,然后转化为数字。
代码如下:
char * freqAlphabets(char * s){
int len = strlen(s);
char* ret = malloc(len);
int retsSize = 0;
//用来转化
char tmp[3];
tmp[2] = '\0';
int i;
for(i = 0; i < len; i++){
//判断是否为j以后的字母
if(i + 2 < len && s[i + 2] == '#'){
tmp[0] = s[i];
tmp[1] = s[i + 1];
int k = atoi(tmp);
ret[retsSize++] = 'j' + (k - 10);
i += 2;
}
else{
ret[retsSize++] = s[i] - '1' + 'a';
}
}
ret[retsSize] = '\0';
return ret;
}
3.5 作为子字符串出现在单词中的字符串数目
题目链接
1967. 作为子字符串出现在单词中的字符串数目
思路分析:
这道题我们只需要将pattern中的每个字符串逐一在word中进行寻找,查看是否为word的子串。
代码如下:
int numOfStrings(char ** patterns, int patternsSize, char * word){
int ret = 0;
for(int i = 0; i < patternsSize; i++){
//判断是否为子串
if(strstr(word, patterns[i])){
ret++;
}
}
return ret;
}