字符串的扩展操作2:
(1)编写一个方法,将字符串中的空格全部替换为"%20".不允许开辟额外的内存空间。
如:"Mr John Smith"替换为"Mr%20John%20Smith";
1)分析:
对字符串(或数组)的操作,通常从字符串的尾部开始编辑,从后往前反向操作,不必担心会覆盖原来的数据。
如:memecpy的函数实现。
2)步骤:
1.先扫描一个字符串,计算出字符串中的空格数;
2.反向编辑字符串,将空格用%20替换。
3)代码实现:
void replaceSpaces(char* str,int length){
int spaceCount=0;
int newLength;
int i;
for(i=0;i<length;i++){
if(str[i]==' ')
spaceCount++;
}
newLength=length+spaceCount*2;//空格为一个字符,%20为3个字符。
str[newLength]='\0';//注意设置串的结束标识;
for(i=length-1;i>=0;i--){//反向扫描
if(' '==str[i]){
str[newLength-1]='0';
str[newLength-2]='2';
str[newLength-3]='%';
newLength=newLength-3;
}
else{
str[newLength-1]=str[i];
newLength=newLength-1;
}
}
}
-------
(2)基本的字符串压缩功能。如果压缩后的字符串没有变短,则返回以前的字符串,否则返回压缩后的字符串。
比如:字符串"aabccccaaa"变成"a2b1c4a3";
1)方法一:
public String compressStr(String str){
String myStr="";
char pre=str.charAt(0);
int count=1;
for(int i=1;i<str.length();i++){
if(str.charAt(i)==pre){
count++;
}
else{
myStr+=pre+""+count;
pre=str.charAt(i);
count=1;
}
}
return myStr+pre+count;//注意最后一组重复字符还未放到压缩字符中。
}
缺点:字符串的拼接部分的时间复杂度为O(n^2);
---
2)优化:使用StringBuffer;
String compressStr(String str){
int size=countCompression(str);//计算压缩后的 长度;
if(size>str.length())
return str;
StringBuffer mystr=new StringBuffer();
char pre=str.charAt(0);
int count=1;
for(int i=1;i<str.length();i++){
if(pre==str.charAt(i)){
count++;
}else{
mystr.append(pre);
mystr.append(count);
pre=str.charAt(i);
count=1;
}
}
mystr.append(pre);
mystr.append(count);
return mystr.toString();
}
/*计算压缩后的字符串的长度*/
int countCompression(String str){
if(null==str || ""==str)
return 0;
int size=0;//size为压缩后的字符串长度。
int count=1;//count为某个字符出现的个数
char pre=str.charAt(0);
for(int i=1;i<str.length();i++){
if(pre==str.charAt(i)){
count++;
}
else{
size=size+1+String.valueOf(count).length();
//将count转为字符串,再计算字符串的长度,再加上一个字符的长度。
pre=str.charAt(i);
count=1;
}
}
size=size+1+String.valueOf(count).length();
return size;
}
----
3)优化,不使用StringBuffer;
String compressStr(String str){
int size=countCompression(str);
if(size>str.length())
return str;
char* array=new char[size];//将压缩后的字符串存入到数组中;
int curIndex=0;//curIndex为数组中的当前索引。
char pre=str.charAt(0);
int count=1;
for(int i=1;i<str.length();i++){
if(pre==str.charAt(i))
count++;
else{
curIndex=setChar(array,pre,count,curIndex);//根据pre,count重新更新curIndex;
pre=str.charAt(i);
count=1;
}
}
index=setChar(array,pre,count,curIndex);
return String.valueOf(array);
}
int setChar(char* array,char c ,int count,int index){
array[index]=c;
index++;
char* cnt=String.valueOf(count).toCharArray();
//将count转换为String,在转为char数组。
for(char x:cnt){
array[index]=x;
index++;
}
return index;
}
----------
(3)若M*N矩阵中某个元素为0,则将其所在的行与列清零。
1)陷阱:
直接遍历整个矩阵,如果遇到某个元素的值为0,则将其所在的行与列清零。陷阱是,在读取被清零的行与列时,以及变成了0,所以最终整个矩阵都会变成0。
2)方法一:
建立一个矩阵,第一次扫描标记0元素的位置,在第二次扫描时,将0元素所在的行与列清零。
空间复杂度为O(M*N)
3)方法二:
将元素值为0的行与列清零,值需要建两个数组,分别记录下它的行号,与列号,即可。
时间复杂度为O(M+N);
实现:
public void setZeros(int ** matrix){
boolean[] row=new boolean[matrix.length];//行数组
boolean[] column=new boolean[matrix[0].length];//列数组
for(int i=0;i<matrix.length;i++){
for(int j=0;j<matrix[0].length;j++){
if(0==matrix[i][j]){
row[i]=true;
column[j]=true;
}
}
}//记录值为0的元素所在的行与列。
for(int i=0;i<matrix.length;i++){
for(int j=0;j<matrix[0].length;j++){
if(row[i] || column[j])
matrix[i][j]=0;
}
}
}
-------
(4)给定两个字符串str1和str2,判断str1是否由str2旋转而来。
如:waterbottle是由erbottlewat旋转而来。
1)分析:
str1如果是由str2旋转而来,满足2个条件;
1.str1与str2的长度相同。
2.str2是str1+str1子串。(+表示连接符)
2)代码实现:
public boolean isRotation(String str1,String str2){
int len1=str1.length();
if(len1==str2.length() && len1>0){
String str1str1=str1+str1;
return isSubString(str1str1,str2);
}
return false;
}
---------------