字符串(String)笔记

本文探讨了字符串在Java、C++和C中的处理方式,包括字符串的不可变性、 substr 和 subString 的区别,以及字符范围。通过四个实例题,讲解了字符串排序、替换、交换和子串变位词问题,涉及到了快速排序、倒序复制等算法。
摘要由CSDN通过智能技术生成

字符串(String)

字符串相关概念

java:String内置类型,引用数据类型,不可更改,要改的话考虑StringBuffer,StringBuilder,char[]
C++:std::string可更改,也可以用char
C:只有char[]
需要注意的是:
1、C++中"+"运算符复杂度未定义,但通常认为是线性的。
2、在C++中std::string substr和java中的String的subString参数不同。
3、字符范围:
C/C++[-128,127]通常转化为undesigned[0,255](跟平台相关)
java[0,65535](跟平台相关)

以下记录几例关于字符串相关的面试题。

例1,0-1交换

把一个0-1串(只包含0和1的串)进行排序,可以交换任意两个位置,问最少交换的次数?
分析:使用快排partition??最左边的0和最右边的1可以不用管
比如000…000001011…111111111

//部分代码如下
int answer=0;
for(int i=0,j=len-1;i<j;++i,--j){
	for(;(i<j)&&(a[i]=='0');++i);
	for(;(j>i)&&(a[j]=='1');--j);
	if(i<j) ++answer;
}

例2,字符串替换和复制

删除一个字符串所有的a,并复制所有的b。注:字符数组足够大(不开辟新空间)
分析:先删除a,可以利用原来字符串的空间

//先删除a,可以利用原来字符串的空间
int n=0,numb=0;
for(int i=0; s[i]; i++){
	if(s[i] != 'a'){s[n++] == s[i];}
	if(s[i] == 'b'){++numb;}
}
s[n]=0;
//再复制b,注意字符串要加长
int newLength = n+numb;
s[newLength]=0;
for(int i=newLength-1,j=n-1;j>=0;--j){
	//这里使用倒着复制的方法,原始的信息不会被覆盖掉,保证原始信息不变
	s[i--]=s[j];
	if(s[j]=='b') s[i--]='b';
}

这题采用了一种惯用技巧**“倒着复制”**(memery copy),可以保证原始信息不会被覆盖。

例3、交换星号

一个字符串只包含*号和数字,请把它的星号都放在开头。
分析:
方法1:快排partition—数字的相对顺序会变化
循环不变式:[0,i-1]都是 星号,[i,j-1]都是数字,[j,n-1]未探测。
交换星号样例

for(int i=0,j=0;j<n;++j){
	if(s[j]=='*') swap(s[i++],s[j]);
}

方法2:采用“倒着复制”,数字相对顺序不变

int j=n-1;
for(int i=n-1;i>=0;--i){
	if(isdigit(s[i])) {
		s[j--]=s[i];//如果i是数字,则复制给j;如果i是*号,则跳过
	}
	for(;j>=0;--j){
		s[j]='*';//当i=-1时,说明数字已经复制完了,则将前面的j都变为*
	}
}

例4、子串变位词

给定两个串a和b,问b是否是a的子串的变位词。例如输入a=hello,b=lel,lle,ello都是true,但是b=elo是false。
分析:滑动窗口思想
这道题典型的滑动窗口思想,动态维护一个窗口。比如b的长度是3,那么我们需要考察a[0,2],[1,3],[2,4]是否和b是变位词。那么该如何跟b比较呢?
我们用一个hash,基于字符串的特殊性,可以用[0,255]或者[0,65535]的数组,暂且认定它们都是小写的英文字母,[0,25]来表示b中每个单词出现的次数。
我们可以存一下有多少个非0次出现,以后有用。

int nonZero = 0;
for(int i=0; i<lenb; i++){
	if(++num[b[i]-'a']==1){//b[i]-'a'就是把b里面的第i位转换成0-25中间的一个数
		++nonZero;//nonZero是统计num数组里面有多少个数字是非0的
	}
}

我们用b中的次数减去a中一个窗口内的字符种类,如果结果全是0,则找到这样的子串。
注意:num[]的含义变为了字符种类差

//第一个窗口[0,lenb-1](注意:lena<lenb无解)
for(int i=0; i<lenb; +++i){
	int c = a[i] - 'a';
	--num[c];
	if(num[c] == 0){
		--nonZero;
	}else if(num[c] == -1){
		++nonZero;
	}
}
if(nonZero == 0) return true;

窗口如何移动?向右移动一位
新窗口a[i-lenb+1, i]
旧窗口a[i-lenb,i-1]
扔掉a[i-lenb],加入a[i]

for(int i=lenb; i<lena; i++){
	int c=a[i-lenb] - 'a';
	++num[c];
	if(num[c]==1) ++nonZero;
	else if(num[c]==0) --nonZero;
	c=a[i]-'a';
	--num[c];
	if(num[c]==0) --nonZero;
	else if(num[c]==-1) ++nonZero;
	if(nonZero==0) return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值