算法训练营第八天|344.反转字符串、541. 反转字符串II、剑指Offer 05.替换空格、151.翻转字符串里的单词、剑指Offer58-II.左旋转字符

64 阅读1分钟

LeetCode 344.反转字符串

和之前反转整个链表的双指针想法类似,但是这题是个数组,数组在内存中是连续的,反转数组和反转链表的做法也是有些不同的,反转数组会更为简单。双指针一个指数组头,一个指数组尾,相向朝着数组中间移动,并且移动过程中互相交换。

class Solution {
    private void swap(char[] s, int i, int j){
        char temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
    public void reverseString(char[] s) {
        int i = 0, j = s.length - 1;
        while(i < j){
            swap(s, i++, j--);
        }
    }
}

LeetCode 541. 反转字符串II

class Solution {
    public String reverseStr(String s, int k) {
        char[] ch = s.toCharArray();
        for(int i = 0; i < ch.length; i += 2 * k){// 1. 每隔 2k 个字符的前 k 个字符进行反转

            // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
            if(i + k <= ch.length){
                reverse(ch, i, i + k - 1);
            }
            else{// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
                reverse(ch, i, ch.length - 1);
            }
        }
        return new String(ch);
    }
    private void reverse(char[] ch, int i, int j){
        while(i < j){
            char temp = ch[i];
            ch[i] = ch[j];
            ch[j] = temp;
            i++;
            j--;
        }
    }
}

剑指 Offer 05. 替换空格

普通解法:

class Solution {
    public String replaceSpace(String s) {
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) != ' '){
                sb.append(s.charAt(i));
            }
            else{
                sb.append("%20");
            }
        }
        return sb.toString();
    }
}

极致做法:

首先扩充数组到每个空格替换成"%20"之后的大小。

然后从后向前替换空格,也就是双指针法,i指向新长度的末尾,j指向旧长度的末尾。

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

151.翻转字符串里的单词

class Solution {
    public String reverseWords(String s) {
        // 1. 移除首位及中间多余空格
        StringBuilder sb = removeSpace(s);
        // 2. 将整个字符串反转
        reverseString(sb, 0, sb.length() - 1);
        // 3. 将每个单词反转
        reverseEachWord(sb);

        return sb.toString();

    }
    private StringBuilder removeSpace(String s){
        int start = 0;
        int end = s.length() - 1;
        while(s.charAt(start) == ' ')start++;
        while(s.charAt(end) == ' ')end--;
        StringBuilder sb = new StringBuilder();
        while(start <= end){
            char c = s.charAt(start);
            if(c != ' ' || sb.charAt(sb.length() - 1) != ' '){
                sb.append(c);
            }
            start++;
        }
        return sb;
    }
    private void reverseString(StringBuilder sb, int start, int end){ // 反转字符串指定区间[start, end]的字符
        while(start < end){
            char temp = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, temp);
            start++;
            end--;
        }
    }
    private void reverseEachWord(StringBuilder sb){
        int start = 0;
        int end = 1;
        int n = sb.length();
        while(start < n){
            while(end < n && sb.charAt(end) != ' '){
                end++;
            }
            reverseString(sb, start, end - 1);
            start = end + 1;
            end = start + 1;
        }
    }
}

剑指Offer58-II.左旋转字符

class Solution {
    public String reverseLeftWords(String s, int n) {
        // 1. 反转区间为前n的子串
        // 2. 反转区间为n到末尾的子串
        // 3. 反转整个字符串
        StringBuilder sb = new StringBuilder(s);
        reverse(sb, 0, n - 1);
        reverse(sb, n, s.length() - 1);
        return sb.reverse().toString();
    }
    private void reverse(StringBuilder sb, int start, int end){
        while(start < end){
            char temp = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, temp);
            start++;
            end--;
        }
    }
}