代码随想录算法训练营第8天|字符串1 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋转字符串

344.反转字符串

建议: 本题是字符串基础题目,就是考察 reverse 函数的实现,同时也明确一下 平时刷题什么时候用 库函数,什么时候 不用库函数
题目链接:344.反转字符串
文章讲解/视频讲解:344.反转字符串

知识点

双指针的应用
reserve库函数的实现
明确平时刷题什么时候用 库函数,什么时候 不用库函数

class Solution {
    public void reverseString(char[] s) {
        int l = 0;
        int r = s.length - 1;
        char temp;
        while(l < r){
            temp = s[l];
            s[l] = s[r];
            s[r] = temp;
            l++;
            r--;         
        }           
    }
}

541. 反转字符串II

建议:本题又进阶了,自己先去独立做一做,然后在看题解,对代码技巧会有很深的体会。
题目链接:541. 反转字符串II
文章讲解/视频讲解:541. 反转字符串II

思路

三种情况分别如何处理

  • 如果剩余字符大于等于 2k
  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
    情况1和3可以共同处理

总结

其实在遍历字符串的过程中,当需要固定规律一段一段去处理字符串的时候,不一定要i++这种,可以让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。
reserve()函数左闭右开,注意边界的处理。

class Solution {
    public String reverseStr(String s, int k) {
        char[] ch = s.toCharArray();
        for(int i = 0; i < ch.length; i+=2*k){
            if(i + k <= ch.length){
                reverse(ch, i, i+k-1); // 1. 剩余字符小于 2k;2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
            }else{
                reverse(ch, i, ch.length-1); // 3. 如果剩余字符少于 k 个,则将剩余字符全部反转。
            }
        }
        return new String(ch);
    }
    // 定义翻转函数
    public void reverse(char[] ch, int i, int j) {
        for (; i < j; i++, j--) {
            char temp  = ch[i];
            ch[i] = ch[j];
            ch[j] = temp;
        }
    }
}

卡码网:54.替换数字

建议:对于线性数据结构,填充或者删除,后序处理会高效的多。好好体会一下。(但是对于java一定要开辟新空间,好像没什么用
题目链接:卡码网:54.替换数字
题目链接/文章讲解:卡码网:54.替换数字

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            if (Character.isDigit(s.charAt(i))) {
                sb.append("number");
            }else sb.append(s.charAt(i));
        }
        System.out.println(sb);
    }
}

###不熟悉的基础语法知识

  • Character.isDigit(s.charAt(i)
  • sb.append(“number”)

拓展

此时算上本题,我们已经做了七道双指针相关的题目了分别是:
27.移除元素
15.三数之和
18.四数之和
206.翻转链表
142.环形链表II
344.反转字符串

151.翻转字符串里的单词 (没有很掌握

建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。
题目链接:151.翻转字符串里的单词
文章讲解/视频讲解:151.翻转字符串里的单词

思路

多余空格的删除----->整体翻转-------->每个单词翻转
视频中讲解的方法直接在原String操作,不适合java,因为String字符串一旦创建就不可改变
首先得把字符串转化成其他可变的数据结构,同时还需要在转化的过程中去除空格。
难点:多余空格的删除

// leecode官方解法1 直接用库函数
class Solution {
    public String reverseWords(String s) {
        // 除去开头和末尾的空白字符
        s = s.trim(); // 这个底层是不是新创建了一个string空间存放处理后的值?
        // 正则匹配连续的空白字符作为分隔符分割
        List<String> wordList = Arrays.asList(s.split("\\s+"));
        Collections.reverse(wordList);
        return String.join(" ", wordList);
    }
}
// leecode官方解法2 自己编写对应函数
class Solution {
    public String reverseWords(String s) {
        StringBuilder sb = trimSpaces(s);

        // 翻转字符串
        reverse(sb, 0, sb.length() - 1);

        // 翻转每个单词
        reverseEachWord(sb);

        return sb.toString();
    }

    public StringBuilder trimSpaces(String s) {
        int left = 0, right = s.length() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s.charAt(left) == ' ') {
            ++left;
        }

        // 去掉字符串末尾的空白字符
        while (left <= right && s.charAt(right) == ' ') {
            --right;
        }

        // 将字符串间多余的空白字符去除
        StringBuilder sb = new StringBuilder();
        while (left <= right) {
            char c = s.charAt(left);

            if (c != ' ') {
                sb.append(c);
            } else if (sb.charAt(sb.length() - 1) != ' ') {
                sb.append(c);
            }

            ++left;
        }
        return sb;
    }

    public void reverse(StringBuilder sb, int left, int right) {
        while (left < right) {
            char tmp = sb.charAt(left);
            sb.setCharAt(left++, sb.charAt(right));
            sb.setCharAt(right--, tmp);
        }
    }

    public void reverseEachWord(StringBuilder sb) {
        int n = sb.length();
        int start = 0, end = 0;

        while (start < n) {
            // 循环至单词的末尾
            while (end < n && sb.charAt(end) != ' ') {
                ++end;
            }
            // 翻转单词
            reverse(sb, start, end - 1);
            // 更新start,去找下一个单词
            start = end + 1;
            ++end;
        }
    }
}

基础语法知识

String.join(" “, wordList); // 将list内容连接成字符串。第一个参数是分隔符。第二个参数是待连接的素材。源码中使用的是stringBuilder。
Arrays.asList(); // 该方法是将数组转化成List集合的方法
Collections.reverse(); // 反转list集合内容
s.split(”\s+"); // “\s+”中的+表示一个或多个的意思

卡码网:55.右旋转字符串

卡码网:55.右旋转字符串
建议:题解中的解法如果没接触过的话,应该会想不到
题目链接/文章讲解:55.右旋转字符串

参考之前做过的剑指offer的基础解法

JZ58 左旋转字符串
需要额外申请一个StringBuilder空间

public class Solution {
	    public String RightRotateString (String str, int n) {
        //取余,因为每次长度为n的旋转数组相当于没有变化
        if(str.isEmpty() || str.length == 0){
            return "";
        }
        //取余,因为每次长度为m的旋转数组相当于没有变化
        int mod = n % str.length();
        StringBuilder res = new StringBuilder();
        for(int i = str.length - mod; i < str.length; i++) res.append(str.charAt(i));
        for(int i = 0; i < mod; i++) res.append(str.charAt(i));

        return res.toSting();
    }
}

看本题文章讲解后

类似上1题,先整体反转,再局部反转
思路就是 通过 整体倒叙,把两段子串顺序颠倒,两个段子串里的的字符在倒叙一把,负负得正,这样就不影响子串里面字符的顺序了
但是对于java来说还是需要一个额外数组空间

// 方法3 代码随想录
public class Solution {

    public String LeftRotateString (String str, int n) {
        //取余,因为每次长度为n的旋转数组相当于没有变化
        if(str.isEmpty() || str.length() == 0)
            return "";
        int m = str.length();
        //取余,因为每次长度为m的旋转数组相当于没有变化
        n = n % m;    

        char[] chars = str.toCharArray();
        reverseString(chars, 0, str.length() - 1);
        reverseString(chars, 0, str.length() - n - 1);
        reverseString(chars, str.length() - n, str.length() - 1);

        return new String(chars);

    }
    public static void reverseString(char[] ch, int start, int end) {
        //异或法反转字符串,参照题目 344.反转字符串的解释
        while (start < end) {
            ch[start] ^= ch[end];
            ch[end] ^= ch[start];
            ch[start] ^= ch[end];
            start++;
            end--;
        }
    }
}

###遇到的不熟悉的基础语法
res.toSting(); // StringBuilder类型转换为字符串
char[] chars = str.toCharArray(); // 字符串转换为一个字符数组
new String(chars); // 字符数组转换为字符串

//异或法反转字符串,参照题目 344.反转字符串的解释
while (start < end) {
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end–;
}

  • 31
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码随想录算法训练是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值