算法记录|Day08字符串

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+k1(表明剩余长度大于2k,则 e n d < c h a r s . l e n g t h − 1 end<chars.length-1 end<chars.length1
  • 不是, 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.length1:i+k1

其实没有必要判断剩余长度是否还有2k,只需要判断end与最后一个元素谁更小。因为上面两种情况下都有 e n d = i + k − 1 end=i+k-1 end=i+k1

 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++;
    }
}

}

反转思路也可以是整体+再局部:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值