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

day08 | LeetCode 344.反转字符串 、541. 反转字符串II、 剑指Offer 05.替换空格、151.翻转字符串里的单词、 剑指Offer58-II.左旋转字符串

文章目录

  • day08 | LeetCode 344.反转字符串 、541. 反转字符串II、 剑指Offer 05.替换空格、151.翻转字符串里的单词、 剑指Offer58-II.左旋转字符串
  • 一、344.反转字符串
    • 方法:双指针
      • 1. 思路
      • 2. 代码实现
      • 3.复杂度分析
      • 3.思考
    • Reference
  • 二、541. 反转字符串II
    • 方法:
      • 1. 思路
      • 2. 代码实现
      • 3. 复杂度分析
    • Reference
  • 三、剑指Offer 05.替换空格
    • 方法:双指针
      • 1. 思路
      • 2. 代码实现
      • 3. 复杂度分析
    • Reference
  • 四、151.翻转字符串里的单词
    • 方法:
      • 1. 思路
      • 2. 代码实现
      • 3. 复杂度分析
    • Reference
  • 五、剑指Offer58-II.左旋转字符串
    • 方法:
      • 1. 思路
      • 2. 代码实现
      • 3. 复杂度分析
    • Reference

一、344.反转字符串

链接:Loading Question… - 力扣(LeetCode)

方法:双指针

1. 思路

  • 定义两个指针,l 为左边界,r 为右边界
  • 通过循环两两交换字符,在字符串中间停下
  • 循环判断条件是 字符串长度 / 2 奇数偶数没有区别

2. 代码实现

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

3.复杂度分析

时间复杂度:O(N)

两个指针一个从头往后,一个从后往前,直到他们相遇,总共会把长度为N的字符数组全部遍历一遍,因此时间复杂度为O(N)

空间复杂度:O(1)

原地修改的字符数组,没有占用和创建其他空间,只有两个常数级的指针

3.思考

  • 如果库函数是题目的主体部分那么就不推荐使用库函数进行解题
  • 如果库函数只是题目中的一个解体步骤,那么可以考虑使用库函数

Reference

  1. 代码随想录 (programmercarl.com)
  2. 字符串基础操作! | LeetCode:344.反转字符串_哔哩哔哩_bilibili

二、541. 反转字符串II

题目:Loading Question… - 力扣(LeetCode)

方法:

1. 思路

  • 主要思考每个规则的实现条件
  • 每隔 2k 个字符的前 k 个字符进行反转
  • 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
  • 剩余字符少于 k 个,则将剩余字符全部反转

2. 代码实现

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

3. 复杂度分析

时间复杂度:O(N)

空间复杂度:O(N)

Reference

  1. 字符串操作进阶! | LeetCode:541. 反转字符串II_哔哩哔哩_bilibili
  2. 代码随想录 (programmercarl.com)

三、剑指Offer 05.替换空格

题目:剑指 Offer 05. 替换空格 - 力扣(LeetCode)

方法:双指针

1. 思路

如果想把这道题目做到极致,就不要只用额外的辅助空间了!使用双指针法,从后向前的替换空格,过程如下:

  1. 首先扩充数组到将每个空格替换成"%20"之后的大小
  2. right指向新数组末尾,left指向旧数组末尾
  3. 遍历left,结束条件为:left ≥0
  4. 如果不是空格,直接用left的元素替换right位置上的元素
  5. 如果是空格,则将right位置替换成"%20"right移动三位,left移动一位

从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素向后移动。其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。

这么做有两个好处:

  • 不用申请新数组
  • 从后向前填充元素,避免了从前先后填充元素要来的 每次添加元素都要将添加元素之后的所有元素向后移动

2. 代码实现

class Solution {
    public String replaceSpace(String s) {
        if(s == null || s.length() == 0){
            return s;
        }
        // 扩充空间
        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){
						// right 左移两位
            if(s.charAt(left) == ' '){
                chars[right--] = '0';
                chars[right--] = '2';
                chars[right] = '%';
            }else{
                chars[right] = chars[left];
            }
            left--;
            right--;
        }
        return new String(chars);
    }
}

3. 复杂度分析

时间复杂度:O(N)

空间复杂度:O(N)

Reference

  1. 代码随想录 (programmercarl.com)

四、151.翻转字符串里的单词

题目:151. 反转字符串中的单词 - 力扣(LeetCode)

方法:

1. 思路

这道题目可以说是综合考察了字符串的多种操作。

所以这里我还是提高一下本题的难度:不要使用辅助空间,空间复杂度要求为O(1)。

我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒序了,那么再把单词反转一下,单词不就正过来了。

解体思路如下:

  • 移除多余空格
  • 将整个字符串反转
  • 将每个单词反转

举例,源字符串为:"the sky is blue “:

  • "the sky is blue”
  • "eulb si yks eht”
  • "blue is sky the”

现在还需要处理的是,需要移除字符串中多余的空格,移除逻辑和 27.移除元素 的逻辑是一模一样的,只不过把移除元素改成了移除空格。

2. 代码实现

class Solution {
      /**
       * 思路:
       * 1. 先移除多余的空格
       * 2. 反转整个字符串
       * 3. 反转每个单词
       * hello word => drow olleh => word hello
       */
    public String reverseWords(String s) {
        char[] chars = s.toCharArray();
        // 1. 移除多余的空格
        chars = removeSpaces(chars);
        // 2. 反转整个字符串
        reverse(chars, 0, chars.length - 1);
//        System.out.println(new String(chars));
        // 3. 反转每个单词
        int start = 0;
        for (int i = 0; i <= chars.length; i++){
            // 到达字符串尾或单词末尾 i == chars.length &&
            if (i == chars.length || chars[i] == ' '){
                reverse(chars, start, i - 1);
                start = i + 1;
            }
        }
        return new String(chars);
    }

    // 1. 使用快慢指针的方法移除字符串多余的空格
    public char[] removeSpaces(char[] chars){
        int slow = 0;
        for(int fast = 0; fast < chars.length; fast++){
            // 移除所有的空格
            if(chars[fast] != ' '){
                // 除第一个单词外,单词开头添加空格
                if(slow != 0) chars[slow++] = ' ';
                // fast 遇到空格代表遍历完一个单词
                while (fast < chars.length && chars[fast] != ' '){
                    chars[slow++] = chars[fast++];
                }
            }
        }
        // 相当于 c++ 中的 resize()
        char[] newChars = new char[slow];
        System.arraycopy(chars, 0, newChars, 0, slow);
        return newChars;
    }
    // 2. 反转字符串
    public void reverse(char[] ch, int start, int end){
        if (end > ch.length){
            System.out.println("set a wrong end");
            return;
        }
        while (start < end){
            ch[start] ^= ch[end];
            ch[end] ^= ch[start];
            ch[start] ^= ch[end];
            start++;
            end--;
        }
    }
}

3. 复杂度分析

时间复杂度:O(N)

空间复杂度:O(1)

Reference

  1. 代码随想录 (programmercarl.com)
  2. 字符串复杂操作拿捏了! | LeetCode:151.翻转字符串里的单词_哔哩哔哩_bilibili

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

题目:力扣 (leetcode.cn)

方法:

1. 思路

提升一下本题难度:不能申请额外空间,只能在本串上操作。

这题可以用 局部反转 + 整体反转 来做:

  • 反转区间为前n的子串
  • 反转区间为n到末尾子串
  • 反转整个字符串

2. 代码实现

class Solution {
    public String reverseLeftWords(String s, int n) {
        char[] chars = s.toCharArray();
        // 反转 前n子串
        reverse(chars, 0, n - 1);
        // 反转 n到末尾的子串
        reverse(chars, n, chars.length - 1);
        // 反转整个字符串
        reverse(chars, 0, chars.length - 1);
        return new String(chars);
    }
    // 反转字符串
    public void reverse(char[] ch, int start, int end){
        while (start < end){
            ch[start] ^= ch[end];
            ch[end] ^= ch[start];
            ch[start] ^= ch[end];
            start++;
            end--;
        }
    }
}

3. 复杂度分析

时间复杂度:O(N)

空间复杂度:O(1)

Reference

  1. 代码随想录 (programmercarl.com)

你可能感兴趣的:(算法,java,leetcode)