代码随想录算法训练营第八天|344.反转字符串、541.反转字符串II、剑指Offer05.替换空格、151.翻转字符串里的单词、剑

143 阅读3分钟

344.反转字符串

题目链接:344.反转字符串

思路:让第一个和最后一个交换位置,第二个和倒数第二个交换位置,依次类推。

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

class Solution {
    public void reverseString(char[] s) {
        char temp = ' ';
        for (int i = 0; i < s.length / 2; i++) {
            temp = s[i];
            s[i] = s[s.length - 1 - i];
            s[s.length - 1 - i] = temp;
        }
    }
}

这里交换数据的时候也可以通过位运算来交换。

class Solution {
    public void reverseString(char[] s) {
        int l = 0;
        int r = s.length - 1;
        while (l < r) {
            s[l] ^= s[r];  //构造 a ^ b 的结果,并放在 a 中
            s[r] ^= s[l];  //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
            s[l] ^= s[r];  //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
            l++;
            r--;
        }
    }
}

541.反转字符串II

题目链接:541.反转字符串II

思路:反转的思路和反转数组一样,就是交换前面和后面的数据。本题重点要对反转的边界条件进行判断。

时间复杂度O(n)

class Solution {
    public String reverseStr(String s, int k) {
        char[] ch = s.toCharArray();
        int len = ch.length;
        for (int i = 0; i < len; i += (2 * k)) {
            int count = 0;
            if (len - i < k) { // 如果剩余字符小于k
                for (int j = i; j < i + (len - i) / 2; j++) {
                    char temp = ch[j];
                    ch[j] = ch[len - 1 - count];
                    ch[len - 1 - count] = temp;
                    count++;
                }
                return String.valueOf(ch);
            }
            for (int j = i; j < i + k / 2; j++) {
                char temp = ch[j];
                ch[j] = ch[i + k - 1 - count];
                ch[i + k - 1 - count] = temp;
                count++;
            }
        }
        return String.valueOf(ch);
    }
}

记录一下随想录中的解法。在进行k的判断的时候更加简便

class Solution {
    public String reverseStr(String s, int k) {
        char[] ch = s.toCharArray();
        for(int i = 0; i < ch.length; i += 2 * k){
            int start = i;
            //这里是判断尾数够不够k个来取决end指针的位置
            int end = Math.min(ch.length - 1, start + k - 1);
            //用异或运算反转 
            while(start < end){
                ch[start] ^= ch[end];
                ch[end] ^= ch[start];
                ch[start] ^= ch[end];
                start++;
                end--;
            }
        }
        return new String(ch);
    }
}

剑指Offer 05.替换空格

题目链接:剑指Offer 05.替换空格

思路:我的实现方法是开辟新的空间来进行赋值操作,这样的话实现十分简单。

时间复杂度O(n)

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

记录随想录上的双指针法,首先将数组扩展到将空格替换成"%20"之后的大小。然后使用双指针从后向前替换空格。(如果是从前向后的话仍然要移动数组中的元素,时间复杂度无法降低)时间复杂度O(n),空间复杂度O(1)

e6c9d24ely1go6qmevhgpg20du09m4qp.gif

class Solution {
    public String replaceSpace(String s) {
        if(s == null || s.length() == 0) return s;
        // 扩充字符串长度
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == ' ') {
                sb.append("  ");
            }
        }
        // sb长度为0说明字符串中没有空格,直接返回
        if (sb.length() == 0) return s;
        int left = s.length() - 1;
        s += sb; // 扩充字符串长度
        int right = s.length() - 1;
        char[] ch = s.toCharArray();
        for (; left >= 0; left--) {
            if (ch[left] == ' ') {
                ch[right--] = '0';
                ch[right--] = '2';
                ch[right--] = '%';
            } else {
                ch[right--] = ch[left];
            }
        }
        return new String(ch);
    }
}

151.翻转字符串里的单词

题目链接:151.翻转字符串里的单词

思路1:首先将多余的空格移除,然后将整个字符串反转,然后再将每个单词进行反转就可以得到目标值。

时间复杂度O(n)

class Solution {
    public String reverseWords(String s) {
        // 去除多余空格
        StringBuilder sb = removeSpace(s);
        // 反转整个字符串
        reverseSting(sb, 0, sb.length() - 1);
        // 反转每个单词
        reverseEachWord(sb);
        return sb.toString();
    }
    public StringBuilder removeSpace(String s) {
        int start = 0, end = s.length() - 1;
        while (s.charAt(start) == ' ') start++; // 删除前面多余空格
        while (s.charAt(end) == ' ') end--; // 删除后面多余空格
        StringBuilder sb = new StringBuilder();
        while (start <= end) {
            // 当s中是空格的时候,判断sb中最后一个是不是空格,如果是说明空格重复,则跳过
            if (s.charAt(start) != ' ' || sb.charAt(sb.length() - 1) != ' ') {
                sb.append(s.charAt(start));
            }
            start++;
        }
        return sb;
    }
    public void reverseSting(StringBuilder s, int start, int end) { // 反转字符串
        while (start < end) {
            char temp = s.charAt(start);
            s.setCharAt(start, s.charAt(end));
            s.setCharAt(end, temp);
            start++;
            end--;
        }
    }
    public void reverseEachWord(StringBuilder s) {
        int start = 0;
        int end = 1;
        while (end < s.length()) {
            while (end < s.length() && s.charAt(end) != ' ') {
                end++;
            }
            reverseSting(s, start, end - 1);
            start = end + 1;
            end = start + 1;
        }
    }
}

思路2:开辟一个新的字符数组,然后倒序填充单词。

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

class Solution {
    public String reverseWords(String s) {
        char[] initialArr = s.toCharArray();
        char[] newArr = new char[s.length() + 1]; // 目标数组,最后一个单词后面也添加空格,多以长度加一
        int k = 0;
        int i = s.length() - 1;
        for (; i >=0; i--) {
            while (i >= 0 && initialArr[i] == ' ') i--; // 跳过空格
            int end = i;
            while (i >=0 && initialArr[i] != ' ') i--; // 找到单词前一个位置
            for (int j = i + 1; j <= end; j++) {
                newArr[k++] = initialArr[j];
                if (j == end) {
                    newArr[k++] = ' ';
                }
            }
        }
        return new String(newArr, 0, k - 1);
    }
}

思路3:反转字符串,反转每个单词,然后通过移位删除多余空格。

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

class Solution {
    public String reverseWords(String s) {
        char[] ch = s.toCharArray();
        reverseString(ch, 0, ch.length - 1); // 反转整个字符串
        int k = 0;
        for (int i = 0; i < ch.length; i++) {
            while (i < ch.length && ch[i] == ' ') i++;
            int start = i; // 单词起始位置
            while (i < ch.length && ch[i] != ' ') i++; // i指向单词结束后面一个
            reverseString(ch, start, i - 1); // 反转单词
            for (int j = start; j < i; j++) { // 移位删除空格
                ch[k++] = ch[j];
                if (j == i - 1) {
                    // 单词后面加空格
                    if (k < ch.length) { // 防止越界
                        ch[k++] = ' ';
                    }
                }
            }
        }
        // 如果字符串没有多余空格,最后一个单词就不会加空格,需要返回k
        return new String(ch, 0, (k == ch.length && ch[k - 1] != ' ') ? k : k - 1);
    }
    public void reverseString(char[] s, int start, int end) {
        while (start < end) {
            s[start] ^= s[end]; // a = a^b
            s[end] ^=  s[start]; // b = a^b^b = a
            s[start] ^= s[end]; // a = a^b^a = b
            start++;
            end--;
        }
    }
}

其实也可以使用split()按照空格分割,然后再倒序拼接,但意义不大。

剑指Offer58-II.左旋转字符串

题目链接:剑指Offer58-II.左旋转字符串

思路:我的做法是开辟新的数组,对数组进行赋值操作,同样实现比较简单但意义不大。

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

class Solution {
    public String reverseLeftWords(String s, int n) {
        char[] result = new char[s.length()];
        int index = 0;
        for (int i = n; i < s.length(); i++) {
            result[index++] = s.charAt(i);
        }
        for (int i = 0; i < n; i++) {
            result[index++] = s.charAt(i);
        }
        return String.valueOf(result);
    }
}

随想录上的方法,先对前k个元素进行反转,然后再对后面的元素进行反转,最后对所有元素进行反转,结果就能够的到目标值。时间复杂度O(n),空间复杂度O(1)

class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder sb = new StringBuilder(s);
        reverseString(sb, 0, n - 1);
        reverseString(sb, n, s.length() - 1);
        reverseString(sb, 0, s.length() - 1);
        return sb.toString();
    }
    public void reverseString(StringBuilder s, int start, int end) {
        while (start < end) {
            char temp = s.charAt(start);
            s.setCharAt(start, s.charAt(end));
            s.setCharAt(end, temp);
            start++;
            end--;
        }
    }
}