数据结构与算法 - 两个指针搞定字符串操作
2013-11-25 11:27
323 查看
在笔试、面试中经常出现对字符串的操作,所以对于字符串的常用操作要熟练掌握。同时也要牢固掌握字符串的基本操作。
在C语言中,可以通过如下的方式来声明字符串:
1、char *str="字符串";// 字符常量
2、char str[]="字符串";// 字符数组
在C++中,可以使用string字符串类型,在Java中可以使用String。但是字符串类型最终都是转换为字符数组进行操作的,只是C++和Java对此做了进一步的封装。
C和C++系统提供的一些函数如下:
字符串的函数有:
(1)strlen()求长度
(2)strcmp()比较字符串的大小
(3)strcpy()字串复制函数 利用标准库函数strncpy(),可以将一字符串的一部分拷贝到另一个字符串中。strncpy()函数有3个参数:第一个参数是目标字符串;第二个参数是源字符串;第三个参数是一个整数,代表要从源字符串拷贝到目标字符串中的字符数
(4)char *strstr(char *str1, char *str2); 从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。
在笔试、面试中,常见到的字符串操作如下:
(1)字符串空格问题:如接收有空格的字符串、去除字符串中间的空格等
(2)字符串顺序:如反转字符串、左旋字符串
(3)求最长回文子串等
下面将详细讲解这几个问题。
1、去除字符串空格
删除字符串开始及末尾的空白符,并且把数组中间的多个空格(如果有)符转化为1个。
在做如上的题目时,需要对指针进行判空操作,这样才体现出程序的健壮性。
2、左旋字符串
将一个字符串左边的n个字符移动到右边即左旋字符串。解决的思路非常多,但是有一个方法感觉比较好。首先想一下,如果要将一个字符串反转,你会怎么做?
(1)设两个指针,一个指向字符串开头start,一个指向字符串末尾end,然后交换指针的值。
(2)start加1,而end减1,直到start>=end为止。
代码如下:
下面来反转字符串。将一个字符串分成两部分,X和Y两个部分,在字符串上定义反转的操作X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么我们可以得到下面的结论:(X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。
不是么?ok,就拿abcdef 这个例子来说,若要让def翻转到abc的前头,那么只要按下述3个步骤操作即可:
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。
如下图所示。
具体的实现代码如下:
3、求最长回文子串
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串连续出现的字符串片段。回文的含义是:正着看和倒着看是相同的,如abba和abbebba。输入字符串长度大于等于1小于等于5000。
由于相同字母组成的一定是回文子串,如a,aa,aaaa,所以在遍历字符串字符时,直接找第i个元素(图中浅绿n)左右两边与该字符不相同的字符,并用两个指针pre和post指向。如下图。
这样就可以将pre--,post++,然后比较*pre和*post的值。如果相等,继续pre--,post++(在操作时注意pre和post的边界条件);如果不相等,记录并更新回文子串的长度即可。
代码如下:
常见的字符串操作非常多,但是如上几个题目有一个共同的特点:那就是使用两个指针就可以搞定这类型的题目。对于第一题和最后一题,是通过数组下标来标识位置的,我们也完全可以使用一个指针来标识,就像中间的两类型题目,使用一个指针来标识位置。所以只要指针操作过关,这类型的题目思路相对简单,解出来的难度不是很大。
参考博客July
在C语言中,可以通过如下的方式来声明字符串:
1、char *str="字符串";// 字符常量
2、char str[]="字符串";// 字符数组
在C++中,可以使用string字符串类型,在Java中可以使用String。但是字符串类型最终都是转换为字符数组进行操作的,只是C++和Java对此做了进一步的封装。
C和C++系统提供的一些函数如下:
字符串的函数有:
(1)strlen()求长度
(2)strcmp()比较字符串的大小
(3)strcpy()字串复制函数 利用标准库函数strncpy(),可以将一字符串的一部分拷贝到另一个字符串中。strncpy()函数有3个参数:第一个参数是目标字符串;第二个参数是源字符串;第三个参数是一个整数,代表要从源字符串拷贝到目标字符串中的字符数
(4)char *strstr(char *str1, char *str2); 从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。
在笔试、面试中,常见到的字符串操作如下:
(1)字符串空格问题:如接收有空格的字符串、去除字符串中间的空格等
(2)字符串顺序:如反转字符串、左旋字符串
(3)求最长回文子串等
下面将详细讲解这几个问题。
1、去除字符串空格
删除字符串开始及末尾的空白符,并且把数组中间的多个空格(如果有)符转化为1个。
# include <stdio.h> # include <math.h> void DelSpace(char *s){ if(s == NULL) return; int flag = 0 ; if(*s == ' ') flag = 1; char *p = s; int j = 0; while(*p != '\0'){ if(*p != ' ') s[j++] = *p; else{ while(*p == ' '){ p++; } // 在首或尾的地方不需要再加入空格,p++可能导致这里的p指向'\0' if(flag==1 || *p=='\0'){ flag = 0; }else{ s[j++] = ' '; } p--;//方便外层的p++做处理 } p++; } s[j] = '\0'; } int main(){ char str[]=" dddd psdf dd "; DelSpace(str); printf("%s",str); }
在做如上的题目时,需要对指针进行判空操作,这样才体现出程序的健壮性。
2、左旋字符串
将一个字符串左边的n个字符移动到右边即左旋字符串。解决的思路非常多,但是有一个方法感觉比较好。首先想一下,如果要将一个字符串反转,你会怎么做?
(1)设两个指针,一个指向字符串开头start,一个指向字符串末尾end,然后交换指针的值。
(2)start加1,而end减1,直到start>=end为止。
代码如下:
char * invert(char *start, char *end) { char tmp, *ptmp = start; while (start != NULL && end != NULL && start < end){ tmp = *start; *start = *end; *end = tmp; start ++; end --; } return ptmp; }
下面来反转字符串。将一个字符串分成两部分,X和Y两个部分,在字符串上定义反转的操作X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么我们可以得到下面的结论:(X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。
不是么?ok,就拿abcdef 这个例子来说,若要让def翻转到abc的前头,那么只要按下述3个步骤操作即可:
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。
如下图所示。
具体的实现代码如下:
char *left(char *s, int pos) //pos为要旋转的字符个数,或长度,下面主函数测试中,pos=3。 { int len = strlen(s); invert(s, s + (pos - 1)); //如上,X->X^T,即 abc->cba invert(s + pos, s + (len - 1)); //如上,Y->Y^T,即 def->fed invert(s, s + (len - 1)); //如上,整个翻转,(X^TY^T)^T=YX,即 cbafed->defabc。 return s; }
3、求最长回文子串
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串连续出现的字符串片段。回文的含义是:正着看和倒着看是相同的,如abba和abbebba。输入字符串长度大于等于1小于等于5000。
由于相同字母组成的一定是回文子串,如a,aa,aaaa,所以在遍历字符串字符时,直接找第i个元素(图中浅绿n)左右两边与该字符不相同的字符,并用两个指针pre和post指向。如下图。
这样就可以将pre--,post++,然后比较*pre和*post的值。如果相等,继续pre--,post++(在操作时注意pre和post的边界条件);如果不相等,记录并更新回文子串的长度即可。
代码如下:
#include <iostream> #include <cstdio> using namespace std; char *x; int length=0; void findCircle(char *str){ if(str==NULL) return; char *pre=NULL,*post=NULL; for(str; *str!='\0'; str++){ pre=str;post=str; while(*(post+1)!='\0'&&*(post+1)==*str) post++; while(*(pre-1)!='\0'&&*(pre-1)==*str) pre--; while( pre-1!=NULL&&post+1!=NULL&& (*(pre-1)==*(post+1)) ){ pre=pre-1; post=post+1; } if(post-pre+1>length) { length=post-pre+1; x=pre; } } for(int i=0;i<length;i++){ cout<<*(x++)<<" "; } } int main(){ char *str; gets(str); findCircle(str); return 0; }
常见的字符串操作非常多,但是如上几个题目有一个共同的特点:那就是使用两个指针就可以搞定这类型的题目。对于第一题和最后一题,是通过数组下标来标识位置的,我们也完全可以使用一个指针来标识,就像中间的两类型题目,使用一个指针来标识位置。所以只要指针操作过关,这类型的题目思路相对简单,解出来的难度不是很大。
参考博客July
相关文章推荐
- 再回首,数据结构——字符串与数组的常见操作(链式存储,包含朴素匹配算法等)
- 【数据结构与算法C】利用两个栈S1S2模拟一个队列,用栈的基本操作实线EnQueue,DeQueue,QueueEmpty
- 数据结构——算法之(010)( 字符串的左旋转操作)
- 数据结构——算法之(012)( linux C 所有字符串操作函数实现)
- 数据结构——算法之(010)( 字符串的左旋转操作)
- 【数据结构与算法】B tree 即相关操作 深入解读
- 数据结构——算法之(005)(判断字符串是否是对称的即(回文字符串))
- .net 数据结构与算法基础:图的操作
- 算法学习-数据结构之链表操作,创建,插入,删除,查找。
- 数据结构与算法学习之队列及队列的相关操作
- 数据结构——算法之(028)( 寻找其中的一个子字符串个数)
- 再回首,数据结构——字符串与数组的常见操作(顺序存储)
- 数据结构实验一--单链表的基本操作的算法
- 数据结构与算法[LeetCode]—两个有序数组合并及找中点问题
- 数据结构与算法——字符串
- 数据结构和算法 (二)数据结构基础、线性表、栈和队列、数组和字符串
- 【数据结构与算法】求二叉树中两个节点的最近祖先
- 数据结构之二叉排序树(基于指针实现基本操作)
- 数据结构与算法——栈的相关操作
- 数据结构-单链队列相关操作算法