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

目录

  • 344.反转字符串
      • 知识点
  • 541. 反转字符串II
      • 思路
      • 总结
  • 卡码网:54.替换数字
      • 拓展
  • 151.翻转字符串里的单词 (没有很掌握
      • 思路
      • 基础语法知识
  • 卡码网:55.右旋转字符串
      • 参考之前做过的剑指offer的基础解法
      • 看本题文章讲解后

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

你可能感兴趣的:(算法,数据结构,java)