字符串
Leecode 题目
344. 反转字符串
206.反转链表,那么反转字符串依然是使用双指针的方法,只不过对于字符串的反转,其实要比链表简单一些。
class Solution {
public void reverseString(char[] s) {
/* if(s.length ==1 ||s == null){
return ;
}
revrse(s,0,s.length-1);
}
public void revrse(char[] s, int i, int j){
if(i>=j){
return;
}
char temp =s[j];
s[j] = s[i];
s[i] = temp;
revrse(s,i+1,j-1);*/
int i=0;
int j= s.length-1;
while(i<j){
char temp =s[j];
s[j] = s[i];
s[i] = temp;
i++;
j--;
}
}
}
总结
常见的交换数值:
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
s[l] ^= s[r]; //构造 a ^ b 的结果,并放在 a 中
s[r] ^= s[l]; //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
s[l] ^= s[r]; //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
利用了异或运算的以下性质:
1、任何数和自己异或都等于0,即x ^ x = 0
2、任何数和0异或都等于自己,即x ^ 0 = x
3、异或运算满足交换律和结合律,即x ^ y = y ^ x,(x ^ y) ^ z = x ^ (y ^ z)
541. 反转字符串 II
每隔2k个反转前k个,尾数不够k个时候全部反转
思路
- 一次循环2k个长度,头指针指向 i i i(for循环, i = i + 2 k i=i+2k i=i+2k)
- 每一次循环需要判断尾指针是否超过数组的长度,谁小取谁
class Solution {
public String reverseStr(String s, int k) {
char[] chars = s.toCharArray();
for(int i = 0; i < chars.length; i += 2 * k){
int end =0;
if(chars.length-i<2*k){ //判断一下剩余的长度是否还大于2k吗
end = chars.length<k+i?chars.length-1:i+k-1; //小于了,就判断一下end和length-1谁更小
}else{
end = i+k-1;
}
reverse(chars,i, end);
}
String res = new String(chars);
return res;
}
public void reverse( char[] chars,int start, int end){
while(end>start){
char temp = chars[start];
chars[start] = chars[end];
chars[end] = temp;
end--;
start++;
}
}
}
判断剩余的长度是否还有2k
- 是, e n d = i + k − 1 end=i+k-1 end=i+k−1(表明剩余长度大于2k,则 e n d < c h a r s . l e n g t h − 1 end<chars.length-1 end<chars.length−1)
- 不是, e n d = c h a r s . l e n g t h < k + i ? c h a r s . l e n g t h − 1 : i + k − 1 end = chars.length<k+i?chars.length-1:i+k-1 end=chars.length<k+i?chars.length−1:i+k−1
其实没有必要判断剩余长度是否还有2k,只需要判断end与最后一个元素谁更小。因为上面两种情况下都有 e n d = i + k − 1 end=i+k-1 end=i+k−1
if(chars.length-i<2*k){
end = chars.length<k+i?chars.length-1:i+k-1; /
}else{
end = i+k-1;
}
//改为:
int end = Math.min(ch.length - 1,start + k - 1);
剑指 Offer 05. 替换空格
题目:请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
思路:改变字符串,StringBuilder或者变成数组
- 方法一:StringBuilder,有空格就在在容器中添加"%20"。
class Solution {
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for(int i=0;i<s.length();i++){
if(s.charAt(i) == ' '){
sb.append("%20");
}else{
sb.append(s.charAt(i));
}
}
return sb.toString();
}
}
- 方法二:变成数组,用到双指针
代码随想录的解析:里面的动图很好的诠释了双指针的用法
其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处: - 不用申请新数组。
- 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
class Solution {
public String replaceSpace(String s) {
//首先统计空格的数量
int count =0;
for(int i=0;i<s.length();i++){
if(s.charAt(i) == ' '){
count++;
}
}
//没有空格,就直接返回
if(count == 0){
return s;
}
// 有空格,双指针
int left = s.length()-1;
char[] res = new char[s.length()+2*count];
int right = res.length-1;
System.out.println(right);
while(left>=0){
if(s.charAt(left)== ' '){
res[right--] ='0';
res[right--] = '2';
res[right--]='%';
left--;
}else{
res[right--]=s.charAt(left--);
}
}
return new String(res);
}
}
151. 反转字符串中的单词
思路:
1.去除字符串中多余的空格
2.将字符串利用双指针截取单词添加到stringbuilder中
class Solution {
public String reverseWords(String s) {
//1.清楚多余的空格
s = removespace(s);
//2.构建一个容器
StringBuilder sb = new StringBuilder();
//(1)使用双指针,遇到空格就停下,截取(i-end)这一段单词
int end = s.length()-1;
for(int i = s.length()-1;i>=0;i--){
if(s.charAt(i)==' '){
sb.append(s.substring(i+1,end+1));
sb.append(" ");
end = i-1;
}else if(i==0){ //(2) 需要注意的是,当i=0时,前面没有空格了,就直接截取
sb.append(s.substring(i,end+1));
}else{}
}
String res = sb.toString();
return res;
}
public String removespace(String s){
// 利用的思路是27题里面删除目标元素
char[] chars = s.toCharArray();
int slow =0;
for(int fast=0;fast<s.length();fast++){
// 这一步表示,当一个单词结束后,需要添加一个空格
if(chars[fast]!=' '){
if(slow!=0){
chars[slow++]=' ';
}
//如果快指针没遇到空格,把值赋给满指针然后一起向前走
while(fast<s.length()&&chars[fast]!=' '){
chars[slow++] = chars[fast++];
}
}
}
//slow以前的所有元素都不包含目标值
char[] newres = new char[slow];
System.arraycopy(chars,0,newres,0,slow);
return new String(newres);
}
}
代码随想录,思路(整体反转+局部反转):
- 移除多余空格 : “the sky is blue”
- 字符串反转:“eulb si yks eht”
- 单词反转:“blue is sky the”
总结
在字符串和字符数组中用到函数
- 求大小,字符串,字符数组都是str.length().记得加括号
- 数组复制,System.arraycopy(源,起始索引,目标,起始索引,长度)
- 字符数组和字符串之间相互转换,str.toCharArray(), new String(chars);
剑指 Offer 58 - II. 左旋转字符串
剑指 Offer 58 - II. 左旋转字符串
不能申请额外空间,只能在本串上操作。
使用substr 和 反转 时间复杂度是一样的 ,都是O(n),但是使用substr申请了额外空间,所以空间复杂度是O(n),而反转方法的空间复杂度是O(1)。
思路:
局部反转+整体反转
class Solution {
public String reverseLeftWords(String s, int n) {
char[] chars = s.toCharArray();
reverse(chars, 0, n-1);
reverse(chars, n, chars.length - 1 );
reverse(chars, 0, chars.length - 1);
return new String(chars);
}
public void reverse(char[] chars, int begin, int end){
while(begin<end){
char temp = chars[begin];
chars[begin] = chars[end];
chars[end] = temp;
end--;
begin++;
}
}
}
反转思路也可以是整体+再局部: