代码随想录算法训练营第八天| 344.反转字符串、541.反转字符串II、替换空格、151.翻转字符串里的单词、左旋转字符串。

344.反转字符串

image-20230323101156661

双指针:

class Solution {
    public void reverseString(char[] s) {
        int left = 0;
        int right = s.length-1;
        while(left < right){
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;

            left++;
            right--;
        }
    }
}

递归实现:

    public void reverseString(char[] s) {
        recursion(s,0,s.length-1);
    }

    public void recursion(char[] s,int left,int right){
        if(left >= right){
            return;
        }
        char temp = s[left];
        s[left] = s[right];
        s[right] = temp;
        recursion(s,left+1,right-1);
        //交换元素和继续递归的代码可以互换
    }

补充:

位运算进行交换:

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 完成交换

541.反转字符串II

image-20230323102321554

暴力解法:

class Solution {
    public String reverseStr(String s, int k) {
        int left = 0;
        int right = 0;//记录2k处
        int mid = 0;//记录k处
        int count = 1;

        char[] ch = s.toCharArray();

        //注意控制边界
        while(left<s.length()){
            System.out.println("count=="+count);
            right = left + 2*k*process(count)-1;
            mid = left + k*process(count)-1;
            System.out.println("right=="+right);
            System.out.println("mid=="+mid);

            if(mid >= s.length()){//说明前面不足k个元素
                System.out.println("mid下标越界");
                reverse(ch,left,s.length()-1);
                break;
            }
            if(right >= s.length()){//足k个元素,但是不足2k个元素
                System.out.println("right下标越界");
                reverse(ch,left,mid);
                break;
            }
            reverse(ch,left,mid);
            //变化left
            left = right+1;
            count++;
        }
        return new String(ch);
    }
	
    //根据轮次辅助计算left mid right
    public int process(int n){
        int result = 0;
        if(result == 0){
            result = 1;
            n--;
        }else{
            while(n>0){
                result = result + result*2;
                n--;
            }
        }
        return result;
    }
	
    //实现反转
    public void reverse(char[] s,int start,int end){
        System.out.println("start=="+start);
        System.out.println("end=="+end);
        while(start < end){
            char temp = s[start];
            s[start] = s[end];
            s[end] = temp;

            start++;
            end--;
        }
    }
}

找规律,用循环。

class Solution {
    public String reverseStr(String s, int k) {
        char[] cs = s.toCharArray();
        int n = s.length();//字符串的长度
        //循环
        for (int l = 0; l < n; l = l + 2 * k) {//l = l + 2 * k下一轮开始处,即left
            int r = l + k - 1;//注意要-1
            //我的三种情况其实都可以统一成一行代码
            reverse(cs, l, Math.min(r, n - 1));
        }
        return String.valueOf(cs);
    }
    void reverse(char[] cs, int l, int r) {
        while (l < r) {
            char c = cs[l];
            cs[l] = cs[r];
            cs[r] = c;
            l++; r--;
        }
    }
}

替换空格

剑指offer 05
image-20230323112610790

对于线性数据结构,填充或者删除,后序处理会高效的多。

双指针法:

i指向新长度的末尾,j指向旧长度的末尾。

image-20230323113019679

class Solution {
    public String replaceSpace(String s) {
        if(s == null || s.length()==0){
            return s;
        }

        int count = 0;
        for(int i=0;i<s.length();i++){
            if(s.charAt(i) == ' '){
                count++;
            }
        }

        char[] ch = new char[s.length()+2*count];
        int newArray = ch.length-1;

        for(int i=s.length()-1;i>=0;i--){//遍历一遍
            if(s.charAt(i) == ' '){
                ch[newArray] = '0';
                ch[--newArray] = '2';
                ch[--newArray] = '%';
            }else{
                ch[newArray] = s.charAt(i);
            }
            newArray--;
        }
        return new String(ch);
    }
}

利用StringBuilder:

public static String replaceSpace(String s) {
        if (s == null) {
            return null;
        }
        //选用 StringBuilder 单线程使用,比较快,选不选都行
        StringBuilder sb = new StringBuilder();
        //使用 sb 逐个复制 s ,碰到空格则替换,否则直接复制
        for (int i = 0; i < s.length(); i++) {
            //s.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型
            //if (" ".equals(String.valueOf(s.charAt(i)))){}
            if (s.charAt(i) == ' ') {
                sb.append("%20");
            } else {
                sb.append(s.charAt(i));
            }
        }
        return sb.toString();
    }
}

151.翻转字符串里的单词

image-20230323115054260

借助ArrayList集合,将s中的每一个单词按序放入list集合中。再倒序遍历list集合,得到最终的结果。

class Solution {
    public String reverseWords(String s) {
        int left = 0;
        while(s.charAt(left) == ' '){
            left++;
        }
        List<String> list = new ArrayList<>();
        //此时left指向不为' '的最左下标
        while(left < s.length()){
            StringBuilder sb = new StringBuilder();
            while(left < s.length() && s.charAt(left) != ' '){
                sb.append(s.charAt(left));
                left++;
            }
            list.add(new String(sb));
            while(left < s.length() && s.charAt(left) == ' '){
                left++;
            }
        }

        StringBuilder result = new StringBuilder();
        for(int i=list.size()-1;i>=0;i--){
            result.append(list.get(i));
            if(i != 0){
                result.append(" ");
            }
        }
        return new String(result);
    }
}

不要使用辅助空间,空间复杂度要求为O(1)。

image-20230323144649076

先整体反转,再局部反转。

public String reverseWords(String s) {
    // System.out.println("ReverseWords.reverseWords2() called with: s = [" + s + "]");
    // 1.去除首尾以及中间多余空格
    StringBuilder  sb = removeSpace(s);
    // 2.反转整个字符串
    reverseString(sb, 0, sb.length() - 1);
    // 3.反转各个单词
    reverseEachWord(sb);
    return sb.toString();
}

//利用StringBuilder进行reverse
public void reverseString(StringBuilder sb,int start,int end){
    //双指针
    while (start < end) {
        char temp = sb.charAt(start);
        sb.setCharAt(start, sb.charAt(end));
        sb.setCharAt(end, temp);
        start++;
        end--;
    }
}

public void reverseEachWord(StringBuilder sb){
    int start = 0;
    int end = 0;

    while(start < sb.length()){//定start
        //注意
        while(end < sb.length() && sb.charAt(end) != ' '){
            end++;
        }
        //此时end是指向空格
        //截取
        reverseString(sb,start,end-1);
        start = end+1;
        end = start;
    }
}

public StringBuilder removeSpace(String s){
    StringBuilder  sb = new StringBuilder();
    int start = 0;
    int end = s.length()-1;
    while(s.charAt(start) == ' '){
        start++;
    }
    while(s.charAt(end) == ' '){
        end--;
    }
    while(start <= end){
        char c = s.charAt(start);
        //※
        if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {//保证有空格的话能加一个空格进来
            sb.append(c);
        }
        start++;
    }
    return sb;
}

左旋转字符串

剑指offer 58

image-20230323160642171

最直接的想法:

class Solution {
    public String reverseLeftWords(String s, int n) {
        if(n >= s.length()){
            return s;
        }
        StringBuilder sb = new StringBuilder();
        for(int i=n;i < s.length();i++){
            sb.append(s.charAt(i));
        }
        for(int i=0;i<n;i++){
            sb.append(s.charAt(i));
        }
        return new String(sb);
    }
}

不能申请额外空间,只能在本串上操作

image-20230323160816590

先局部,再整体。

class Solution {
    public String reverseLeftWords(String s, int n) {
        int len=s.length();
        StringBuilder sb=new StringBuilder(s);
        reverseString(sb,0,n-1);//反转前n
        reverseString(sb,n,len-1);//反转后面
        return sb.reverse().toString();//整体反转
    }
    public void reverseString(StringBuilder sb, int start, int end) {
        while (start < end) {
            char temp = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, temp);
            start++;
            end--;
        }
    }
}

image-20230323161145831

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值