代码随想录算法训练营第七天|344.反转字符串、541. 反转字符串II、剑指Offer 05.替换空格、151.翻转字符串里的单词、剑指Offer58-II.左旋转字符串

344.反转字符串 

建议: 本题是字符串基础题目,就是考察 reverse 函数的实现,同时也明确一下 平时刷题什么时候用 库函数,什么时候 不用库函数 

题目链接/文章讲解/视频讲解:代码随想录

如果题目关键的部分直接用库函数就可以解决,建议不要使用库函数。

毕竟面试官一定不是考察你对库函数的熟悉程度, 如果使用python和java 的同学更需要注意这一点,因为python、java提供的库函数十分丰富。

如果库函数仅仅是 解题过程中的一小部分,并且你已经很清楚这个库函数的内部实现原理的话,可以考虑使用库函数。

双指针从首尾向中间移动,交换两指针指向的位置的元素,用一个中间值item保存,实现两元素交换。

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

        while( left < right){
            char item = s[left];
            s[left] = s[right];
            s[right] = item;

            left++;
            right--;
        }
    }
}

541. 反转字符串II

建议:本题又进阶了,自己先去独立做一做,然后在看题解,对代码技巧会有很深的体会。 

题目链接/文章讲解/视频讲解:代码随想录

 没做出来,写复杂了,没想到 i += (2 * k)

其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。

因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。

所以当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。

操作字符串或数组时,如果发现让我们一段一段去处理的时候,for循环的i可以成段成段的去跳。

class Solution {
    public String reverseStr(String s, int k) {
        char[] charset = s.toCharArray();
        for(int i = 0; i < charset.length; i += 2*k){
            int left = i;
            // 判断尾数够不够k个来取决right指针的位置
            int right = Math.min(charset.length - 1,i + k - 1);

            while( left < right){
                char temp = charset[left];
                charset[left] = charset[right];
                charset[right] = temp;

                left++;
                right--;
            }
        }
        return new String(charset);
    }
}
class Solution {
    public String reverseStr(String s, int k) {
        char[] charset = s.toCharArray();
        // 1. 每隔 2k 个字符的前 k 个字符进行反转
        for(int i = 0; i < charset.length; i += 2*k){
            // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
            if(i + k <= charset.length){
                reverse(charset, i, i + k - 1);
                continue;
            }
            // 3. 剩余字符少于 k 个,则将剩余字符全部反转
            reverse(charset, i, charset.length - 1);
        }
        return new String(charset);
    }

    private void reverse(char[] charset, int left, int right){
        while( left < right){
            char temp = charset[left];
            charset[left] = charset[right];
            charset[right] = temp;

            left++;
            right--;
        }
    }
}

剑指Offer 05.替换空格 

建议:对于线性数据结构,填充或者删除,后序处理会高效的多。好好体会一下。

题目链接/文章讲解:代码随想录

双指针法:

很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。

这么做有两个好处:

  1. 不用申请新数组。
  2. 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
//双指针法
public String replaceSpace(String s) {
    if(s == null || s.length() == 0){
        return s;
    }
    //扩充空间,空格数量2倍
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
        if(s.charAt(i) == ' '){
            str.append("  ");
        }
    }
    //若是没有空格直接返回
    if(str.length() == 0){
        return s;
    }
    //有空格情况 定义两个指针
    int left = s.length() - 1;//左指针:指向原始字符串最后一个位置
    s += str.toString();
    int right = s.length()-1;//右指针:指向扩展字符串的最后一个位置
    char[] chars = s.toCharArray();
    while(left>=0){
        if(chars[left] == ' '){
            chars[right--] = '0';
            chars[right--] = '2';
            chars[right] = '%';
        }else{
            chars[right] = chars[left];
        }
        left--;
        right--;
    }
    return new String(chars);
}

 数组复制法:

class Solution {
    //使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制
    public String replaceSpace(String s) {
        if(s == null) return null;

        //选用 StringBuilder 单线程使用,比较快,选不选都行
        StringBuilder sb = new StringBuilder();
        //使用 sb 逐个复制 s ,碰到空格则替换,否则直接复制
        for(int i = 0; i< s.length(); i++){
            if (s.charAt(i) == ' '){
                sb.append("%20");
            }else{
                sb.append(s.charAt(i));
            }
        }
        return sb.toString();
    }
}

151.翻转字符串里的单词 

建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。 

题目链接/文章讲解/视频讲解:代码随想录

解题思路:

  • 移除多余空格
  • 将整个字符串反转
  • 将每个单词反转
class Solution {
    public String reverseWords(String s) {
        char[] chars = s.toCharArray();

        // 1.去除首尾以及中间多余空格
        int slow = 0;
        int size = chars.length;
        for(int fast = 0; fast < size; fast++){
            if( (chars[fast] != ' ') || (fast > 0 && chars[fast-1] != ' ')){
                chars[slow++] = chars[fast];
            }
        }
        if(chars[slow - 1] == ' '){
            slow--;
        }
        size = slow;

        // 2.反转整个字符串
        reverse(chars, 0, size - 1);

        //3.反转各个单词
        int temp = 0;
        for(int fast = 0; fast < size; fast++){
            if(chars[fast] == ' '){
                reverse(chars, temp, fast-1);
                temp = fast + 1;
            }
        }
        reverse(chars, temp, size-1);
        return new String(chars, 0, size);
    }

    public void reverse(char[] chars, int left, int right){
        while(left < right){
            char temp = chars[left];
            chars[left] = chars[right];
            chars[right] = temp;
            left++;
            right--;
        }
    }
}

剑指Offer58-II.左旋转字符串 

建议:题解中的解法如果没接触过的话,应该会想不到

题目链接/文章讲解:代码随想录

这道题目类似上一题翻转字符串里的单词,依然可以通过局部反转+整体反转 达到左旋转的目的。

具体步骤为:

  1. 反转区间为前n的子串
  2. 反转区间为n到末尾的子串
  3. 反转整个字符串

最后就可以达到左旋n的目的,而不用定义新的字符串,完全在本串上操作。

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 left, int right){
        while(left < right){
            char temp = chars[left];
            chars[left] = chars[right];
            chars[right] = temp;
            left++;
            right--;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值