文章目录
- 541. 反转字符串 II
- 发现了三个基础知识的问题
- 看答案改进
- 剑指 Offer 05. 替换空格
- 答案方法1
- 答案方法2
- 知识点
- 一、
- 二、
- 三、
- 总结
541. 反转字符串 II
发现了三个基础知识的问题
第一个
这个题目发现了一个非常大的问题,有点不知道自己的Java基础到底有多少窟窿要去补……太可怕了
一开始我写的代码中对字符串的长度的写法是:
然后出现错误提示:
这个时候我发现,正确的写法应该是:
int length=s.length();
因为length是一个方法啊!你如果不加括号,那和一个属性怎么区分呢?
第二个
在反转数组时,想对数组中的元素进行交换操作,我写的是:
但是提示错误:
也就是说,字符串不能像字符数组一样访问数组中的某个元素,字符串不是数组,想要进行这种操作,需要先将字符串转换为字符数组,用字符串的toCharArray()方法,然后字符数组转换为字符串,比较简单,可以直接new:
char[] c=new char[]{'a','b','c'};
String str=new String(c);
第三个
一开始我在写代码的过程中,检查了很多遍,都没有问题,但是就是结果不对,后来发现是对字符串的知识掌握不牢固,在自定义方法中是相对字符串元素进行交换,但是如果这是不产生一个新的字符串来存储交换后的内容而是直接输出方法中的形参的字符串,字符串并不会改变,因为字符串在底层是由数组存储的,而数组具有不变性。
错的代码:
class Solution {
public String reverseStr(String s, int k) {
int length=s.length();
if(length<k){
return reverse(s,0,length-1);//正确
}else if(length>=k&&length<2*k){
return reverse(s,0,k-1);
}else{
int num=0;
while(num<length&&(num+k)<length){
reverse(s,num,num+k-1);//虽然生成了新的字符串,
//但是没有用字符串接收这个新的字符串,可以直接赋给s
//这样s就存储了新的字符串
num=num+2*k;
}
if((length-num)<k&&(length-num)>0){
reverse(s,num,length-1);//不正确,首先s此时还是
//没有交换的字符串,其次,应该直接在语句前面加上return,
//不然新的字符串根本没机会返回
}
if((length-num)>=k&&(length-num)<2*k){
reverse(s,num,num-1);//不正确,同上
}
return s;//目前返回的是老的字符串,根本没有进行任何改变
}
}
public String reverse(String s,int start,int end){
char temp;
int length=end-start+1;
char[] c=s.toCharArray();
for(int i=0;i<(int)(length/2);i++){
temp=c[start+i];
c[start+i]=c[end-i];
c[end-i]=temp;
}
return new String(c);//这里返回的是新的字符串
}
}
正确的:
class Solution {
public String reverseStr(String s, int k) {
int length=s.length();
if(length<k){
return reverse(s,0,length-1);
}else if(length>=k&&length<2*k){
return reverse(s,0,k-1);
}else{
int num=0;
while(num<length&&(num+k)<length){
s=reverse(s,num,num+k-1);
num=num+2*k;
}
if((length-num)<k&&(length-num)>0){
return reverse(s,num,length-1);
}
if((length-num)>=k&&(length-num)<2*k){
return reverse(s,num,num-1);
}
}
return s;
}
public String reverse(String s,int start,int end){
char temp;
int length=end-start+1;
char[] c=s.toCharArray();
for(int i=0;i<(int)(length/2);i++){
temp=c[start+i];
c[start+i]=c[end-i];
c[end-i]=temp;
}
return new String(c);
}
}
看答案改进
答案的意思是,因为题目有很多相似的处理过程,可以考虑对for循环进行一个修改,答案的代码真简单,厉害
主要省代码的地方就是,在end这个指针的处理上,即判断剩下的节点还够不够k个
答案简化思路:先设置一个头指针,每次for循环都加上2k个,然后指定尾指针,尾指针是根据头指针+k个-1的位置大小和字符数组最后一个元素的位置大小进行比较,取最小值,然后判断头指针和为指针的大小来决定是否进入循环,循环中是交换两个元素,不管情况怎样,最后返回一个新建的字符串
但在写代码过程中,又发现了一个问题,就是对数组来说,如果写成:
会报错:
也就是说,数组中是没有length这个方法的,因为他根本就不是一个类,而是基本数据类型,所以根本就没有方法,数组的工具类是Arrays,不过就算是数组的工具类,也没有length这个方法!因为length是数组中的一个属性,根本不用方法就可获得
根据答案思路改写的代码:
public String reverseStr(String s, int k) {
char[] c=s.toCharArray();
int start,end;
for(int i=0;i<c.length;i+=2*k){
start=i;
end=Math.min(c.length-1,start+k-1);
while(start<end){
char temp=c[start];
c[start]=c[end];
c[end]=temp;
start++;
end--;
}
}
return new String(c);
}
剑指 Offer 05. 替换空格
答案方法1
class Solution {
public String replaceSpace(String s) {
if(s==null||s.length()==0){
return s;
}
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){//可以直接用s.length()这个方法在这
if(s.charAt(i)==' '){//注意,这个方法的返回值,还有单引号
sb.append("%20");
}else{
sb.append(s.charAt(i));//这里也可以直接写,把cgarAt方法包进去
}
}
return sb.toString();
}
}
答案方法2
class Solution {
public String replaceSpace(String s) {
if(s==null||s.length()==0){
return s;
}
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){//这里是将新建的StringBuilder
//的空间大小设为s中空格的两倍
if(s.charAt(i)==' '){//一个空格
sb.append(" ");//添加两个空格
}
}
//其实还有别的办法,比如先遍历一下s中有几个空格num,然后最后创建的
//时候,用s.length()+num*2也行
String newStr=sb.toString()+s;//这样新建的字符串大小就是
//将s中所有的空格替换为%20后的大小
char[] ch1=s.toCharArray();
char[] ch2=newStr.toCharArray();
int left=0;
int right=0;
while(left<s.length()){//这个方法是从头开始添加元素
if(ch1[left]==' '){
ch2[right++]='%';
ch2[right++]='2';
ch2[right]='0';
}else{
ch2[right]=ch1[left];
}
left++;
right++;
}
return new String(ch2);
}
}
知识点
一、
一开始做这个题,想到了用字符串的方法:replaceAll(),然后又碰到了一个小问题,就是:
出现错误:
说明不能前面是字符,后面是字符串,前面既使用字符串的双引号,中间也可以只放一个字符,但是如果两个一个用单引号,一个用双引号,就出错,因为这个方法的两个参数都是字符串类型的:
二、
1、这个题看答案中都用到了StringBuilder,而且都用到了Stringbuilder的toString()方法,这个方法返回的是字符串,也就是返回的是StringBuilder中的具体内容
2、在答案的方法1中用到了charAt()方法,这个方法是String中的,返回的是char型,所以要注意两边的 类型要一致,一开始写成了:
出现错误:
都是因为类型不匹配造成的,首先第一个错误是左边是一个char,基本数据类型,这时
=
=
==
==比较的就是具体的值,而引用数据类型比较的是地址
第二个左边是一个String,右边是一个字符,不能这样赋值
三、
答案方法2中用到了双指针方法,思想是:先通过新建一个空间为将空格替换为%20后大小的字符串,将新的字符串和旧的字符串合并之后赋给s,然后一个指针指向原来的带有空格的旧字符串的末尾索引,一个指向新的空的字符串的末尾索引,然后两个指针一起移动,如果旧的字符串中是空格,新的字符串中就加入% 2 0,然后两个指针前移……(前提是已经转换成了字符数组),这时选择前移是因为,就的字符串在开头部分,而如果要将就的字符串中的空格改成%20,就需要将空格后的部分后移。
其实这个题也可以从头开始添加,这种情况需要不将两个字符串合并,这时不用后移元素,直接向后一个个添加即可
字符串转换为字符数组时使用toCharArray()方法,将StringBuilder转换为char数组,可以先通过用toString()方法,将StringBuilder转换为String,然后再转换
总结
1、数组中的属性有length,直接写s.length==0即可,但是String中没有这个属性,只有方法,所以是s.length()==0
2、在基本数据类型中
=
=
==
==比较的是具体值,而引用数据类型中比较的是地址值,比较内容的话要用重写后的equals()方法,而String中已经重写过了
3、几个方法:
String中的toCharArray():将String转换为char数组
new String(ch):将char数组的内容新建成一个字符串
String中的toString():返回一个字符串
String中的charAt(i):找String中的索引为i的元素
String中的replaceAll(a,b):参数两个都是String类型
StringBuilder中的toString():返回一个字符串,可将StringBuilder转换为String
4、String的不变性:
如果在传入String 的s后,对s进行修改,改完后没有将修改后的字符串赋给s,而是直接将sreturn,这时的s和原来的没有改变,这也是这两个题中,在return时,基本上都是:return new String(ch); 的原因