字符串简介
字符串实际上是一个 unicode 字符
数,可以执行几乎所有在数组中使用的操作。
下面将介绍一些在处理字符串时应该注意的问题。这些特性在不同的语言之间可能有很大不同。
比较函数
字符串有他自己的比较函数
然而,存在这样一个问题:
我们可以用
==
来比较两个字符串吗?
这取决于下面这个问题的答案:
我们使用的语言是否支持运算符重载?
- 如果答案是 yes (例如 C++)。我们可以使用
==
来比较两个字符串。 - 如果答案是 no (例如 Java),我们可能无法使用
==
来比较两个字符串。当我们使用==
时,它实际上会比较这两个对象是否是同一个对象。 - 关于C,字符串的比较函数为
strcmp
,不能用==
来比较两个字符串。关于strcmp的相关介绍见【传送门】小白函数笔记本
关于运算符重载
是否可变
不可变意味着一旦字符串被初始化,你就无法改变它的内容。
- 在某些语言(如 C++、C)中,字符串是可变的。 也就是说,你可以像在数组中那样修改字符串。
- 在其他一些语言(如 Java)中,字符串是不可变的。 此特性将带来一些问题。 我们将在下一篇文章中阐明问题和解决方案。
额外操作
要了解内置操作的时间复杂度。
在计算解决方案的时间复杂度时,不要忘记考虑内置操作的时间复杂度。
不可变字符串——问题和解决方案
在上文中,应该已经知道某门语言中的字符串是否为不可变的。如果字符串是不可变的,则会带来一些问题。
修改操作
不可变字符串无法被修改。哪怕你只是想修改其中的一个字符,也必须创建一个新的字符串。
小心Java中的字符串
在 Java 中,由于字符串是不可变的,因此在连接时首先为新字符串分配足够的空间,复制旧字符串中的内容并附加到新字符串。
解决方案
- 如果你确实希望你的字符串是可变的,则可以将其转换为字符数组。
- 如果你经常必须连接字符串,最好使用一些其他的数据结构,如
StringBuilder
。
相应程序练习
1. 二进制求和
题目
- 给定两个二进制字符串,返回他们的和(用二进制表示)。
- 输入为非空字符串且只包含数字 1 和 0。
输入: a = “11”, b = “1”
输出: “100”
思路
- 满二进一
“奇淫巧计”
奇淫巧计一:巧用三目运算符
下面两种代码,实现效果一样,哪一种更简洁呢?
length = length1>length2?(length1+1):(length2+1);
if(length1>length2) length=length1+1;
else length=length2+1;
再比如,一个比较两个数大小的max函数
代码:
int max(int a, int b){
return a>b?a:b;
}
int max(int a, int b){
if(a>b) return a;
else return b;
}
哪个更简洁呢?
奇淫巧计二:妙用ASCII码
因为这个程序涉及到进位,仅仅只靠字符自然是不能使代码最简洁明了,所以我们需要使用到ASCII码。
从1
到'1'
的转换,你还在用if(a='1') c = 1;
吗?
c = a-'0';
它不香吗?
奇淫巧计三:用sum存储进位信息
问:从后往前遍历,难道每个位子时候进位都需要记录下来?
答:这确实需要记录下来。
问:但是要开一个数组来一一记录吗?
答:只需要一个实时更新的变量来存储进位信息!(本程序的变量名为sum
)
值得注意的是
关于if()
关于if()
条件判断语句,如果()里面有多个条件,从左往右一一遍历。
除非,&&中,有一为0则整个为0;||中,有一为1则整体为1,后面不再遍历。
关于字符串数组
字符串总是以'\0'
作为结束符。因在再给一个字符串分配空间的时候,需要多给一个字符的空间存放结束符'\0'
。不然很容易出现数组越界或者其他情况。
举例:"hello"的长度其实为6,分配的空间为sizeof(char) * 6
。
代码
char * addBinary(char * a, char * b){
int length,length1=strlen(a),length2=strlen(b),sum=0,i=length1-1,j=length2-1,k,num;
length = length1>length2?(length1+1):(length2+1);
char *c=(char *)malloc(sizeof(char)*(length+1));
c[0]='0';c[length]='\0';
k=length-1;
while(i>-1||j>-1||sum)
{
num=(i>-1?a[i]-'0':0)+(j>-1?b[j]-'0':0)+sum;
sum=0;
if(num>1)
{
sum=1;
num-=2;
}
c[k--]=num+'0';
j--;i--;
}
if(c[0]=='0')
{
for(i=0;i<length-1;i++)
c[i]=c[i+1];
c[length-1]='\0';
}
return c;
}
执行结果
2. 实现strStr()
题目
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
输入: haystack = “hello”, needle = “ll”
输出: 2
方法一:暴力解决
【注意】字符串为空字符串的表示:
*needle==NULL
代码如下:
int strStr(char * haystack, char * needle){
int len1=strlen(haystack), len2=strlen(needle);
if(*needle==NULL) return 0;
if(len1<len2) return -1;
for(int i=0; i<len1; i++){
int flag = 0;
for(int j=0; j<len2; j++){
if(haystack[i+j]!=needle[j]){
flag = 1;
break;
}
}
if(!flag) return i;
}
return -1;
}
执行效果:
虽然代码行数少,但是运行时间实在惨不忍睹,这终究不是一段好代码。寻求突破口:KMP算法以及KMP算法的改进算法。
KMP算法解析传送门
方法二:KMP算法
日后补上
3. 最长公共前缀
题目
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
输入: [“flower”,“flow”,“flight”]
输出: “fl”
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
思路
从上往下,每个比一比。
主要是特例的考虑:输入为[]
和[""]
的时候。
if(!strsSize) return "";
if(ch=='\0' && i==0) flag=0;
代码
char * longestCommonPrefix(char ** strs, int strsSize){
if(!strsSize) return "";
int len1 = strlen(strs[0]); char ch;
char * s = (char *)malloc(sizeof(char) * (len1+1));
for(int i=0; i<len1+1; i++){
ch = strs[0][i];
int flag=1;
if(ch=='\0' && i==0) flag=0;
for(int j=1; j<strsSize && flag; j++)
if(ch!=strs[j][i]) flag = 0;
if(!flag){
s[i] = '\0';
break;
}
else s[i] = ch;
}
return s;
}
执行效果
转载:https://blog.csdn.net/AuthurWhywat/article/details/105045106