代码随想录算法训练营第九天| LeetCode151. 反转字符串中的单词 | 卡码网:55.右旋转字符串 | 28. 实现 strStr() | 459.重复的子字符串

目录

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

题目链接:55. 右旋字符串(第八期模拟笔试) (kamacoder.com)

题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

题目链接:459. 重复的子字符串 - 力扣(LeetCode)


  Tomorrow is always fresh with no mistakes in it yet.  

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

要求:不要使用辅助空间,空间复杂度要求为O(1)。在原字符串上进行操作,解题思路如下:

1. 移除前导和尾随空格;

2. 反转整个字符串;

3. 反转每个单词并去除多余空格;

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

  • 移除多余空格 : "the sky is blue"
  • 字符串反转:"eulb si yks eht"
  • 单词反转:"blue is sky the"

这里面有许多小坑需要仔细填,如使用双指针找到单词的开头与结尾,两个单词之间添加空格,设置记录处理后新字符串长度变量的作用等等。

另外如果比较熟悉正则表达式和一些String的API的话,就可以使用StringBuilder偷懒快速解决了。我也在函数reverseWords2也给出了偷懒做法。

class Solution151 {
    public String reverseWords(String s) {
        char[] chars = s.toCharArray();
        int n = chars.length;

        // 移除前导和尾随空格
        int start = 0, end = n - 1;
        while (start <= end && chars[start] == ' ')
            start ++;
        while (start <= end && chars[end] == ' ')
            end --;
        if (start > end)
            return ""; // 只有空格的情况

        // 反转整个字符串
        reverse(chars, start, end);

        // 反转每个单词并去除多余空格
        int i = start, j = start; // 双指针法 定位每个单词
        int newLength = start;  // 记录处理后的新字符串长度
        while (i <= end){
            while (i <= end && chars[i] == ' ')
                i++;  // 找到单词的开始
            if (i > end)
                break;
            // 在两个单词之间添加空格
            if (newLength > start)
                chars[newLength++] = ' ';
            j = i;
            while (j <= end && chars[j] != ' ')
                j++;  // 找到单词的结尾

            reverse(chars, i ,j - 1);  // 反转单词
            while (i < j) {
                chars[newLength++] = chars[i++];  // 将反转后的单词复制到新位置
            }
        }
        return new String(chars, start, newLength - start);
    }

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

    // 使用正则表达式和相关函数的偷懒做法
    public String reverseWords2(String s) {
        s = s.trim(); // 去除首尾空格
        String[] words = s.split("\\s+"); // 匹配一个或多个连续的空白字符. 用于分割单词
        StringBuilder result = new StringBuilder();  // 创建一个 StringBuilder 来存储结果

        // 反向遍历单词数组
        for (int i = words.length - 1; i >= 0; i--) {
            result.append(words[i]);
            if (i != 0){
                result.append(" ");
            }
        }
        return result.toString();
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

题目链接:55. 右旋字符串(第八期模拟笔试) (kamacoder.com)

实现字符串右旋转的一个有效方法是①先反转整个字符串,然后②反转前 k 个字符,再③反转剩余的字符。这样我们可以在原地完成旋转操作,而不需要额外的空间。

需要注意如果k大于字符串长度,要取 k 的模,即 k % n。

class KamaCoder151 {
    public String rightRotate(String s, int k) {
        int n = s.length();
        k = k % n;  // 如果k大于字符串长度,取 k 的模
        char[] chars = s.toCharArray();

        // 反转整个字符串
        reverse(chars, 0, n - 1);
        // 反转前 k 个字符
        reverse(chars, 0, k - 1);
        // 反转剩余的字符
        reverse(chars, k, n - 1);

        return new String(chars);
    }

    // 反转字符数组的子数组
    private void reverse(char[] chars, int left, int right) {
        while (left < right) {
            char temp = chars[left];
            chars[left] = chars[right];
            chars[right] = temp;
            left++;
            right--;
        }
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

要在字符串 haystack 中找到字符串 needle 的第一个匹配项的下标,可以使用多种方法,例如朴素字符串匹配算法或更高效的KMP算法

KMP算法先留个坑🕳。

Leet用户吐槽:“你不能因为 KMP 是教科书上的算法就把它标为简单题吧😅”

使用朴素字符串匹配算法,直接逐个比较 haystack 中的子字符串和 needle。

class Solution28 {
    public int strStr(String haystack, String needle) {
        int hLen = haystack.length();
        int nLen = needle.length();

        if (nLen == 0){
            return 0;
        }

        for (int i = 0; i <= hLen - nLen; i++) {
            int j = 0;
            while (j < nLen && haystack.charAt(i + j) == needle.charAt(j))
                j ++;

            if (j == nLen){
                return i;  // 找到匹配项
            }
        }
        return -1;
    }
}

题目链接:459. 重复的子字符串 - 力扣(LeetCode)

🕳++;

-----------------------------------------------------------------------------------------------------------------

提供一个不容易想到的思路:

  1. 将字符串 s 与自身连接,得到新字符串 s' = s + s;
  2. 去掉 s' 的第一个字符和最后一个字符,得到新字符串 t;
  3. 如果在 t 中能找到 s,说明 s 是由其某个子串重复多次构成的。

这种方法的原理在于,若 s 可以由某个子串 t 重复多次构成,则在 s + s 中会包含 s 的重复模式。思考❓

class Solution459 {
    public boolean repeatedSubstringPattern(String s) {
        String doubled = s + s;
        String trimmed = doubled.substring(1,doubled.length() - 1);
        return trimmed.contains(s);
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值