2014-05-05 19:44:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
2014-05-07 11:24:51 +08:00
|
|
|
|
字符串常见的问题:
|
|
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
* 单词反转/移动/回文判断
|
|
|
|
|
|
* 字符(串)统计
|
2015-11-28 17:06:08 +08:00
|
|
|
|
* 字符串的压缩
|
|
|
|
|
|
* 字符串的排列和组合
|
|
|
|
|
|
* 字符串比较
|
|
|
|
|
|
* 子串
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 翻转句子中单词的顺序
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
|
2014-05-05 19:44:01 +08:00
|
|
|
|
例如输入“I am a student.”,则输出“student. a am I”。
|
|
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2015-12-02 00:05:23 +08:00
|
|
|
|
char *revert_by_word(char *source);
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
2021-08-02 13:31:30 +08:00
|
|
|
|
思路:
|
|
|
|
|
|
|
|
|
|
|
|
* 原地逆序,字符串2边的字符逐个交换 , 再按单词逆序;
|
|
|
|
|
|
* 也可以先按单词逆序,再对整个句子逆序;
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
针对不允许临时空间的情况,也就是字符交换不用临时空间,可以使用的方法有:
|
|
|
|
|
|
|
|
|
|
|
|
1. 异或操作
|
2014-05-07 11:24:51 +08:00
|
|
|
|
2. 也就是2个整数相互交换一个道理
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
char a = 'a', b = 'b';
|
|
|
|
|
|
a = a + b;
|
|
|
|
|
|
b = a - b;
|
|
|
|
|
|
a = a - b;
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
2015-12-01 12:51:40 +08:00
|
|
|
|
最终示例代码:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2021-08-17 17:39:37 +08:00
|
|
|
|
//反转
|
2015-12-02 00:05:23 +08:00
|
|
|
|
void _reverse(char *start,char *end){
|
|
|
|
|
|
if ((start == NULL) || (end == NULL)) return;
|
|
|
|
|
|
while(start < end){
|
|
|
|
|
|
char tmp = *start;
|
|
|
|
|
|
*start = *end;
|
|
|
|
|
|
*end = tmp;
|
|
|
|
|
|
|
|
|
|
|
|
start++,
|
|
|
|
|
|
end--;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *revert_by_word(char *source){
|
|
|
|
|
|
char *end = source;
|
|
|
|
|
|
char *start = source;
|
|
|
|
|
|
if (source == NULL) return NULL;
|
2021-08-17 17:39:37 +08:00
|
|
|
|
|
|
|
|
|
|
//end指针挪动到尾部
|
2015-12-02 00:05:23 +08:00
|
|
|
|
while (*end != '\0') end++;
|
|
|
|
|
|
end--;
|
|
|
|
|
|
|
2021-08-17 17:39:37 +08:00
|
|
|
|
//先全部反转
|
2015-12-02 00:05:23 +08:00
|
|
|
|
_reverse(start,end);
|
|
|
|
|
|
|
2021-08-17 17:39:37 +08:00
|
|
|
|
//按单词反转
|
2015-12-02 00:05:23 +08:00
|
|
|
|
start=end=source;
|
|
|
|
|
|
while(*start != '\0'){
|
|
|
|
|
|
if (*start == ' '){
|
|
|
|
|
|
start++;
|
|
|
|
|
|
end++;
|
|
|
|
|
|
}else if(*end == ' ' || *end == '\0'){
|
|
|
|
|
|
_reverse(start,end-1);
|
|
|
|
|
|
start = end;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
end++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return source;
|
2015-12-01 12:51:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2014-05-07 11:24:51 +08:00
|
|
|
|
类似的题目还有:
|
2015-11-28 21:12:00 +08:00
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
不开辟用于交换数据的临时空间,如何完成字符串的逆序
|
2014-05-07 11:24:51 +08:00
|
|
|
|
用C语言实现一个revert函数,它的功能是将输入的字符串在原串上倒序后返回。
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 左旋转字符串
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
>字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
|
|
|
|
|
|
|
2021-08-02 13:31:30 +08:00
|
|
|
|
如把`字符串abcdef`左旋转2位得到`字符串cdefab` 。请实现字符串左旋转的函数。要求时间对长度为n的字符串操作的复杂度为O(n),辅助内存为O(1)。
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char *left_rotate(char *str,int offset){
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2021-08-02 13:31:30 +08:00
|
|
|
|
|
2021-08-17 17:39:37 +08:00
|
|
|
|
思路: 我们可以abcdef分成两部分,ab和cdef,内部逆序以后,整体再次逆序,就可以得到想要的结果了。
|
|
|
|
|
|
也就是跟上面的问题是同样的问题。
|
|
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 判断字符串是否是回文
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
2021-08-02 13:31:30 +08:00
|
|
|
|
> 回文,如 abcdcba
|
|
|
|
|
|
|
2014-05-07 11:24:51 +08:00
|
|
|
|
分析: 2个指针,一头一尾,逐个比较,都相同就是回文
|
|
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2015-12-01 16:26:04 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* eg acdeedca
|
|
|
|
|
|
* @ret 0 success , -1 fail
|
|
|
|
|
|
*/
|
|
|
|
|
|
int is_huiwen(const char *source){
|
|
|
|
|
|
if (source == NULL || source == '\0') return -1;
|
|
|
|
|
|
char *head = source;
|
|
|
|
|
|
char *tail = source;
|
|
|
|
|
|
while(*tail != '\0'){
|
|
|
|
|
|
tail++;
|
|
|
|
|
|
}
|
|
|
|
|
|
tail--;
|
|
|
|
|
|
|
|
|
|
|
|
while(head < tail){
|
|
|
|
|
|
if (*head != *tail){
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
head++;
|
|
|
|
|
|
tail--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 找到第一个只出现一次的字符
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
在一个字符串中找到第一个只出现一次的字符。如输入ahbaccdeff,则输出h。
|
|
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2015-12-01 16:26:04 +08:00
|
|
|
|
char char_first_appear_once(const char *source)
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
思路一: 蛮力统计, O(n^2)复杂度
|
|
|
|
|
|
思路二: 使用hash表,2次扫描,第一次建立hash表 key为字符,value为出现次数;第二次扫描找到第一个value为1的key,时间复杂度O(n)
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
hash表长度 256,字符直接作为key值。需要注意的是 char 的范围是 -128~127,unsigned char 才是0~255
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
示例代码:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char char_first_appear_once(const unsigned char *source){
|
|
|
|
|
|
int hash[256]={0};
|
|
|
|
|
|
char *tmp = source;
|
|
|
|
|
|
if (tmp == NULL) return '\0';
|
|
|
|
|
|
while(*tmp != '\0'){
|
|
|
|
|
|
hash[*tmp]++;
|
|
|
|
|
|
tmp++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tmp = source;
|
|
|
|
|
|
while(*tmp != '\0'){
|
|
|
|
|
|
if (hash[*tmp] == 1) return *tmp;
|
|
|
|
|
|
tmp++;
|
|
|
|
|
|
}
|
|
|
|
|
|
return '\0';
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
题目扩展:这里的字符换成整数,整数数量几十TB,海量数据处理,显然hash方法不可能,没有那么大得内容
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 统计文章里单词出现的次数
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2014-05-07 11:24:51 +08:00
|
|
|
|
设计相应的数据结构和算法,尽量高效的统计一片英文文章(总单词数目)里出现的所有英文单词,按照在文章中首次出现的顺序打印输出该单词和它的出现次数。
|
|
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
|
|
|
|
|
void statistics(char *string)
|
2014-05-13 09:19:55 +08:00
|
|
|
|
void statistics(FILE *fd)
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
延伸:
|
|
|
|
|
|
|
|
|
|
|
|
如果是海量数据里面统计top-k次数的单词呢?
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 替换空格
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
实现一个函数,把每个空格替换成 "%20",如输入“we are happy”,则输出“we%20are%20happy”
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char *replce_blank(char *source)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
主要问题是一个字符替换成3个字符,替换后的字符串比原串长。
|
|
|
|
|
|
如果想要在原串上直接修改,就不能顺序替换。且原串的空间应该足够大,能容纳替换变长以后的字符串。如果空间不够,就要新建一块空间来保存替换的结果了。这里假设空间足够
|
|
|
|
|
|
|
|
|
|
|
|
1. 第一遍扫描,统计空格个数 n, 替换后的字符串长度 = 原长度+2*n
|
|
|
|
|
|
2. 从后向前扫描字符串,挪动每个字符的位置。注意碰到空格的地方
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char *replace_blank(char *source){
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
char *tail = source;
|
|
|
|
|
|
if (source == NULL) return NULL;
|
|
|
|
|
|
while(*tail != '\0'){
|
|
|
|
|
|
if (*tail == ' ') count++;
|
|
|
|
|
|
tail++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(count){
|
|
|
|
|
|
if(*tail != ' '){
|
|
|
|
|
|
*(tail+2*count) = *tail;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
*(tail+2*count) = '0';
|
|
|
|
|
|
*(tail+2*count-1) = '2';
|
|
|
|
|
|
*(tail+2*count-2) = '%';
|
|
|
|
|
|
count--;
|
|
|
|
|
|
}
|
|
|
|
|
|
tail--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return source;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 小写字母排在大写字母的前面
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
有一个由大小写组成的字符串,现在需要对他进行修改,将其中的所有小写字母排在大写字母的前面(大写或小写字母之间不要求保持原来次序),如有可能尽量选择时间和空间效率高的算法 c语言函数原型:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
void proc(char *str)
|
|
|
|
|
|
```
|
|
|
|
|
|
分析:
|
|
|
|
|
|
|
|
|
|
|
|
比如:HaJKPnobAACPc,要小写字母前面且不要求保存顺序,可以是:anobcHJKPAACP
|
|
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
1. 小写字母 a~z 的 ASCII码值是 97~122,A~Z的 ASCII码值是 65~90;0~9 的ASCII码是 48~57
|
|
|
|
|
|
2. 两边向中间扫描,左边大写右边小写就交换;如果都小写,头指针向前知道找到大写;如果都是大写,尾指针向后找小写;
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
示例代码
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2015-12-02 00:05:23 +08:00
|
|
|
|
char *proc(char *str){
|
|
|
|
|
|
char *start = str;
|
|
|
|
|
|
char *end = str;
|
|
|
|
|
|
if (str == NULL) return NULL;
|
|
|
|
|
|
while(*end != '\0') end++;
|
|
|
|
|
|
end--;
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
while(start < end){
|
|
|
|
|
|
if (*start >= 'A' && *start <= 'Z'){//大写
|
|
|
|
|
|
if (*end >= 'a' && *end <= 'z'){
|
|
|
|
|
|
char tmp = *start;
|
|
|
|
|
|
*start = *end;
|
|
|
|
|
|
*end = tmp;
|
|
|
|
|
|
|
|
|
|
|
|
start++;
|
|
|
|
|
|
}
|
|
|
|
|
|
end--;
|
|
|
|
|
|
}else{//小写
|
|
|
|
|
|
if (*end >= 'A' && *end <= 'Z'){
|
|
|
|
|
|
end--;
|
|
|
|
|
|
}
|
|
|
|
|
|
start++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return str;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 实现字符串转整型的函数
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
也就是实现函数atoi的功能,这道题目考查的就是对各种情况下异常处理。比如:
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
2021-08-02 13:31:30 +08:00
|
|
|
|
以`213`分析转换成证书的过程。`3+1x10+2x100` ,思路是:每扫描到一个字符,把 `之前得到的数字*10`,再加上当前的数字
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
* 0开头,"0213"
|
|
|
|
|
|
* 正/负数,"-432" ,"--422","++23"
|
|
|
|
|
|
* 浮点数,"43.2344"
|
|
|
|
|
|
* 非法,"2123des"
|
|
|
|
|
|
* 存在空格," -32"," +432"," 234","23 432","353 "," + 321"
|
|
|
|
|
|
* NULL/空串,这时候返回值0
|
|
|
|
|
|
* 溢出,"32111111112222222222222222222222222222222" , 与 `INT_MAX `比较
|
|
|
|
|
|
* 如何区分正常的'0'和异常情况下返回的结果"0"? 可以通过一个全局变量 g_status 来标示,值为 kValid/kInvalid。
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
int atoi(const char *str){
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
详细过程也可以[参考这里](http://blog.csdn.net/v_july_v/article/details/9024123)
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 删除串中指定的字符
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
删除指定的字符以后,后面的字符都要向前移动一位。这种复杂度是O(N^2);那么有没有O(N)的方法呢?
|
|
|
|
|
|
|
|
|
|
|
|
比如 "abcdeccba" 删除字符 "c"。使用2个指针,一前一后,比较前面的指针和删除字符:
|
|
|
|
|
|
|
|
|
|
|
|
1. 不相等,两个指针一起跑,且前面的指针值拷贝到后面指针指向的空间
|
|
|
|
|
|
2. 相等时,快指针向前一步
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char *delete_occurence_character(char *src , char target){
|
|
|
|
|
|
char *front = src;
|
|
|
|
|
|
char *rear = src;
|
|
|
|
|
|
while(*front != '\0'){
|
|
|
|
|
|
if (*front != target){
|
|
|
|
|
|
*rear = *front;
|
|
|
|
|
|
rear++;
|
|
|
|
|
|
}
|
|
|
|
|
|
front++;
|
|
|
|
|
|
}
|
|
|
|
|
|
*rear = '\0';
|
|
|
|
|
|
return src;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 在字符串中删除特定的字符
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
题目:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”。
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
这是上个题目的升级版本。
|
|
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
```
|
2015-12-02 00:05:23 +08:00
|
|
|
|
char *delete_occurence_characterset(char *source,const char *del);
|
2015-12-01 16:26:04 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
1. 蛮力法。 遍历字符串,每个字符去删除字符串集合中查找,有就删除
|
2015-12-02 00:05:23 +08:00
|
|
|
|
2. 使用上面的方式,一次遍历
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 删除字符串中的数字并压缩字符串
|
2015-12-02 16:46:09 +08:00
|
|
|
|
|
|
|
|
|
|
如字符串”abc123de4fg56”处理后变为”abcdefg”。注意空间和效率。(下面的算法只需要一次遍历,不需要开辟新空间,时间复杂度为O(N))
|
|
|
|
|
|
这道题跟上一道题也是一个意思。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
示例代码:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char *trim_number(char *source){
|
|
|
|
|
|
char *start = source;
|
|
|
|
|
|
char *end = source;
|
|
|
|
|
|
if (source == NULL) return NULL;
|
|
|
|
|
|
while(*end != '\0'){
|
|
|
|
|
|
if (*end < '0' || *end > '9' ){
|
|
|
|
|
|
*start = *end;
|
|
|
|
|
|
start++;
|
|
|
|
|
|
}
|
|
|
|
|
|
end++;
|
|
|
|
|
|
}
|
|
|
|
|
|
*start = '\0';
|
|
|
|
|
|
return source;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 字符串中找出连续最长的数字串
|
2015-12-02 16:46:09 +08:00
|
|
|
|
|
|
|
|
|
|
写一个函数,功能:
|
|
|
|
|
|
|
|
|
|
|
|
在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串赋值给其中一个函数参数outputstr所指内存。
|
|
|
|
|
|
|
|
|
|
|
|
例如:"abcd12345ed125ss123456789"的首地址传给intputstr后,函数将返回9,outputstr所指的值为123456789
|
|
|
|
|
|
|
|
|
|
|
|
它的原形是:
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
2015-12-02 15:06:16 +08:00
|
|
|
|
```
|
2015-12-02 16:46:09 +08:00
|
|
|
|
int longest_continuious_number(const char *input,char *output)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
应该有3个指针,第一个指针指向一个当前最长数字串的第一个数字,第二个指针指向第二个数字串的第一个数字,第三个指针是遍历指针,且统计第二个数字串的长度;当统计出来的长度大于第一个数字串的长度,第一个指针指向第二个指针指向的数字,相反,第二个指针和第三个指针继续向后查找。
|
|
|
|
|
|
|
2015-12-05 00:55:44 +08:00
|
|
|
|
|
|
|
|
|
|
1. 当end首次碰到数字时,且tmp=0,说明是首次出现数字,第二个指针移到该数字,继续遍历
|
|
|
|
|
|
2. 如果数字后面还是数字,tmp!=0 就是第二个数字串,因此 tmp += 1;
|
|
|
|
|
|
3. 当end从数字到普通字符时,如果tmp > max ,就要修改max和第一个指针start ,并把tmp归为0
|
|
|
|
|
|
|
2015-12-02 16:46:09 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
int longest_continuious_number(const char *input,char *output){
|
|
|
|
|
|
int max = 0;
|
|
|
|
|
|
char *start= input;
|
|
|
|
|
|
char *mid = input;
|
|
|
|
|
|
char *end = input;
|
|
|
|
|
|
int tmp = 0;
|
|
|
|
|
|
if (input == NULL || output == NULL) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (*end != '\0'){
|
|
|
|
|
|
if (*end < '0' || *end < '9'){//字母
|
|
|
|
|
|
if(tmp > max){
|
|
|
|
|
|
max = tmp;
|
|
|
|
|
|
start = mid;
|
|
|
|
|
|
}
|
|
|
|
|
|
tmp = 0;
|
|
|
|
|
|
}else{//数字
|
|
|
|
|
|
if (tmp == 0){//发现数字
|
|
|
|
|
|
mid = end;
|
|
|
|
|
|
}
|
|
|
|
|
|
tmp++;
|
|
|
|
|
|
}
|
|
|
|
|
|
end++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//修改已数字结尾的bug
|
|
|
|
|
|
if(tmp > max){
|
|
|
|
|
|
max = tmp;
|
|
|
|
|
|
start = mid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//copy
|
|
|
|
|
|
int i=0;
|
|
|
|
|
|
while(i<max){
|
|
|
|
|
|
*(output+i) = *(start+i);
|
|
|
|
|
|
i++;
|
|
|
|
|
|
}
|
|
|
|
|
|
*(output+i)='\0';
|
|
|
|
|
|
|
|
|
|
|
|
return max;
|
|
|
|
|
|
}
|
2015-12-02 15:06:16 +08:00
|
|
|
|
```
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 求最大连续递增数字串
|
2015-12-05 00:55:44 +08:00
|
|
|
|
|
|
|
|
|
|
如“ads3sl456789DF3456ld345AA”中的“456789”就是所求。这道题在上一道题目的基础上增加了数字要递增的条件。思路跟上面差不多,碰到不递增的数字就相当于第二个数字串了。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 最长公共子串问题
|
2015-12-05 00:55:44 +08:00
|
|
|
|
|
|
|
|
|
|
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
|
|
|
|
|
|
|
|
|
|
|
|
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,则输出它们的长度4,并打印任意一个子串。
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
int longest_common_subsequence(const char *s1,const char *s2, char *common)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
分析:求最长公共子串(Longest Common Subsequence,LCS)是一道非常经典的动态规划题,因此一些重视算法的公司像MicroStrategy都把它当作面试题。如"abccade","dgcadde"的最大子串为"cad"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
实例代码:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
int longest_common_subsequence(const char *s1,const char *s2, char *common){
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 对称子字符串的最大长度
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2014-05-07 11:24:51 +08:00
|
|
|
|
分析:可能很多人都写过判断一个字符串是不是对称的函数,这个题目可以看成是该函数的加强版。
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
int max_symmetrical_char_length(const char *scr);
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
* 思路一:蛮力法,3重循环(类似 求子数组的最大和 fmax(i,j)问题), fmax(i,j)区间i,j是最长的对称字符
|
|
|
|
|
|
* 思路二:遍历所有子串,然后判读是否对称 O(n^2)
|
|
|
|
|
|
* 思路三:有个O(n)复杂度的算法 http://www.cnblogs.com/McQueen1987/p/3559497.html 分析过程如下:
|
2015-12-02 16:46:09 +08:00
|
|
|
|
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-12-02 15:06:16 +08:00
|
|
|
|
```
|
|
|
|
|
|
int max_symmetrical_char_length(const char *scr){
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 子串匹配的个数
|
2015-11-28 17:06:08 +08:00
|
|
|
|
|
|
|
|
|
|
已知一个字符串,比如asderwsde,寻找其中的一个子字符串比如sde的个数,如果没有返回0,有的话返回子字符串的个数。
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2015-12-05 00:55:44 +08:00
|
|
|
|
char *substr_count(const char *src, const char *substr, int *count)
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 15:21:47 +08:00
|
|
|
|
|
|
|
|
|
|
## 字符串原地压缩
|
|
|
|
|
|
|
|
|
|
|
|
题目描述:“abeeeeegaaaffa" 压缩为 "abe5ag3f2a",请编程实现。
|
|
|
|
|
|
|
|
|
|
|
|
这道题需要注意:
|
|
|
|
|
|
1. 单个字符不压缩
|
|
|
|
|
|
2. 注意考虑压缩后某个字符个数是多位数(超过10个)
|
|
|
|
|
|
3. 原地压缩最麻烦的地方就是数据移动
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这是使用2个指针,一前一后,如果不相等,都往前移动一位;如果相等,后一位变为数字2,且移动后面的指针一位,任然相等则数字加1,不相等
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
char *compress(const char *src,char *dest){
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
上面的压缩算法可以看到,压缩算法的`效率`验证依赖`给定字符串的特性`,如果'aaaaaaaa....aaa' 这样特征的字符串,使用上面的压缩算法,压缩率接近100%,相反,可能会的0%的压缩率。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 请编写能直接实现strstr()函数功能的代码。
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-12-05 00:55:44 +08:00
|
|
|
|
> strstr(str1,str2) 判断str2是否是str1的子串。
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
```
|
2015-12-05 00:55:44 +08:00
|
|
|
|
/*
|
|
|
|
|
|
@ret 有就返回第一次出现子串的地址,否则返回NULL
|
|
|
|
|
|
*/
|
|
|
|
|
|
char *strstr(const char *source, const char *target){
|
|
|
|
|
|
|
2015-12-02 15:06:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 匹配兄弟字符串
|
2015-12-02 15:06:16 +08:00
|
|
|
|
|
|
|
|
|
|
如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串,问如何在迅速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。
|
|
|
|
|
|
|
|
|
|
|
|
思路:判断各自素数乘积是否相等。更多方法请参见:http://blog.csdn.net/v_JULY_v/article/details/6347454。
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
int isBrother(const char *first,const char *secd)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
思路一: 循环匹配 指数级复杂度
|
|
|
|
|
|
思路二: 利用质数,平方和比较,但这样必须是2个串的长度要一样,需要的空间比较大,最多256个字节。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
示例代码:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
int isBrother(const char *first,const char *secd){
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 字符串的排列
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
题目:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。输入字符串 abcca,则输出由 a,b,c排列出来的所有字符串,字符出现个数不变
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
分析:这是一道很好的考查对递归理解的编程题
|
|
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
简单的回溯就可以实现了。当然排列的产生也有很多种算法,去看看组合数学,还有逆序生成排列和一些不需要递归生成排列的方法。
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
2015-11-28 17:06:08 +08:00
|
|
|
|
>印象中Knuth的<TAOCP>第一卷里面深入讲了排列的生成。这些算法的理解需要一定的数学功底,也需要一定的灵感,有兴趣最好看看。
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## n个字符串联接
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
有n个长为m+1的字符串,如果某个字符串的最后m个字符与某个字符串的前m个字符匹配,则两个字符串可以联接,问这n个字符串最多可以连成一个多长的字符串,如果出现循环,则返回错误。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 字符串的集合合并
|
2015-12-02 00:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。
|
|
|
|
|
|
|
2015-12-05 00:55:44 +08:00
|
|
|
|
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
2021-08-02 13:27:19 +08:00
|
|
|
|
## 编写strcpy 函数
|
2015-12-01 16:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
已知strcpy 函数的原型是:
|
|
|
|
|
|
```
|
|
|
|
|
|
char *strcpy(char *strDest, const char *strSrc);
|
|
|
|
|
|
```
|
|
|
|
|
|
其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-07 11:24:51 +08:00
|
|
|
|
|
2014-05-05 19:44:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|