剑指 Offer 58 - II. 左旋转字符串

剑指 Offer 58 - II. 左旋转字符串

对于此题,如果用允许开辟新空间的算法,那么会比较简单,需要将n个字符移到原字符串的后面,所以考虑新字符串从位置为n处开始添加原字符串中的字符,再从0遍历至n,添加原字符串中的字符。
对于给定的k,因为此题给定了k < s.length。但我们为了追求普适性,可以看出一躺s.length次数得到的新字符串和原字符串相同,所以可以对k取模,即k %= s.length

点击查看代码
class Solution {
    public String reverseLeftWords(String s, int n) {
        if(null == s || s.isBlank()) return s;
        StringBuilder sb = new StringBuilder();
        int l = s.length();
        n = n % l;
        for(int i = n; i < l; i++) sb.append(s.charAt(i));
        for(int i = 0; i < n; i++) sb.append(s.charAt(i));
        return sb.toString();
    }
}
再考虑常数空间的算法,我们分析反转后的结果与反转前的结果。 反转前:

[0, 1, 2, 3, ..., n - 1, n, n + 1, n + 2,... , s.length - 1]
反转后:

[n, n + 1, n + 2,... , s.length - 1, 0, 1, 2, 3, ..., n - 1,]

然后再考虑如何反转可以在常数空间内由上式得下式。
可发现先对于反转的两个部分,他们的相对次序依旧保持不变,而是两个部分的次序发生了变化,由此推断由多次反转组成。故而先有全局反转后,将[n - s.length-1][0, n-1]两个部分的次序调整,再观察发现两个部分依然都是保持着升序,所以需要对每个部分的次序再次反转,最后即可得到结果。

点击查看代码
class Solution {
    public String reverseLeftWords(String s, int n) {
        if(null == s || s.isBlank()) return s;
        int l = s.length();
        n = n % l;
        char[] str = s.toCharArray();
        // 反转[0, s.length - 1]
        int start = 0, end = l - 1;
        swap(str, start, end);
        start = 0; end = l - n - 1;
        swap(str, start, end);
        start = l - n; end = l - 1;
        swap(str, start, end);
        return new String(str);
    }

    private void swap(char[] str, int start, int end) {
        while(start < end) {
            char temp = str[start];
            str[start] = str[end];
            str[end] = temp;
            start++; 
            end--;
        }
    }

}
posted @ 2022-01-17 22:30  NullPointer_C  阅读(34)  评论(0)    收藏  举报