代码随想录一刷-Day08

Offer58-II.左旋转字符串

使用中间数组很容易

public String reverseLeftWords(String s, int n) {

    if (n == 0 || s == null || s.length() == 0) {
        return s;
    }
    // 使用中间数组
    char[] tempChars = new char[n];

    char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        // 将 n 位前的字符放入中间数组
        if (i < n) {
            tempChars[i] = chars[i];
            continue;
        }
        // 将 n 位及之后的字符前移 n 位
        chars[i - n] = chars[i];
    }

    for (int i = 0; i < n; i++) {
        // 将中间数组的字符放回原数组
        chars[chars.length - n + i] = tempChars[i];
    }

    return String.valueOf(chars);
}

时间复杂度:O(n)
空间复杂度:O(n)

如果追求降低空间复杂度,进行原地移动,则需要三步:

  1. 反转 [0, n) 位的字符
  2. 反转 [n, len) 位的字符
  3. 反转整个字符

Carl 的题解:

 public String reverseLeftWords(String s, int n) {
     char[] chars = s.toCharArray();
     reverse(chars, 0, chars.length - 1);
     reverse(chars, 0, chars.length - 1 - n);
     reverse(chars, chars.length - n, chars.length - 1);
     return new String(chars);
 }

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

时间复杂度:O(n)
空间复杂度:O(1)

补充:通过三次异或操作 ^= 可以交换两个变量的值,这样可以省略中间变量,但是当两个变量指向同一个对象时,这个操作会有问题,应当谨慎使用



LeetCode28. 实现 strStr()

KMP 经典使用方式

public int strStr(String haystack, String needle) {

    if (needle.length() == 0) {
        return 0;
    }

    int[] next = getNext(needle.toCharArray());

    int j = -1;
    for (int i = 0; i < haystack.length(); i++) {
        while (j >= 0 && haystack.charAt(i) != needle.charAt(j + 1)) {
            j = next[j];
        }
        if (haystack.charAt(i) == needle.charAt(j + 1)) {
            j++;
        }
        if (j == needle.length() - 1) {
            return (i - needle.length() + 1);
        }
    }

    return -1;
}

private int[] getNext(char[] needleChars) {

    // 生成 next 数组
    int[] next = new int[needleChars.length];
    // 1. 初始化
    // j 指向前缀的尾字符
    int j = -1;
    next[0] = j;
    // i 指向后缀的尾字符,从 1 开始
    for (int i = 1; i < needleChars.length; i++) {
        // 2. 处理前后缀不相同的情况
        while (j >= 0 && needleChars[i] != needleChars[j + 1]) {
            j = next[j];
        }
        // 3. 处理前后缀相同的情况
        if (needleChars[i] == needleChars[j + 1]) {
            j++;
        }
        next[i] = j;
    }
    return next;
}

时间复杂度: O(n + m)
空间复杂度: O(m)

KMP 算法另述



LeetCode459.重复的子字符串

看了 Carl 哥的题解才知道,这是道数学题

Carl 题解:

public boolean repeatedSubstringPattern(String s) {
    if (s.equals("")) return false;

    int len = s.length();
    // 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了
    s = " " + s;
    char[] chars = s.toCharArray();
    int[] next = new int[len + 1];

    // 构造 next 数组过程,j从0开始(空格),i从2开始
    for (int i = 2, j = 0; i <= len; i++) {
        // 匹配不成功,j回到前一位置 next 数组所对应的值
        while (j > 0 && chars[i] != chars[j + 1]) j = next[j];
        // 匹配成功,j往后移
        if (chars[i] == chars[j + 1]) j++;
        // 更新 next 数组的值
        next[i] = j;
    }

    // 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值
    if (next[len] > 0 && len % (len - next[len]) == 0) {
        return true;
    }
    return false;
}

时间复杂度: O(n)
空间复杂度: O(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值