题目描述

链接:https://leetcode-cn.com/problems/reverse-string

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

示例 1
输入:[“h”,”e”,”l”,”l”,”o”]
输出:[“o”,”l”,”l”,”e”,”h”]

示例 2
输入:[“H”,”a”,”n”,”n”,”a”,”h”]
输出:[“h”,”a”,”n”,”n”,”a”,”H”]

题解

如果不考虑题目条件,可以考虑使用 StringBuilder 的 reverse() 反转方法。

  1. class Solution {
  2. public void reverseString(char[] s) {
  3. StringBuilder builder = new StringBuilder(String.valueOf(s));
  4. s = builder.reverse().toString().toCharArray();
  5. }
  6. }

根据题目要求:不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间

思路 - 对称交换

直接将字符数组第一个与最后一个互换位置,第二个与倒数第二个互换位置即可。

  1. class Solution {
  2. public void reverseString(char[] s) {
  3. int length = s.length;
  4. for (int i = 0; i < length / 2; i++) {
  5. char temp = s[i];
  6. s[i] = s[length - 1 -i];
  7. s[length - 1 - i] = temp;
  8. }
  9. }
  10. }

双指针思想

对于长度为 N 的待被反转的字符数组,我们可以观察反转前后下标的变化,

  1. 反转前字符数组为 s[0] s[1] s[2] … s[N - 1];
  2. 反转后字符数组为 s[N - 1] s[N - 2] … s[0];
  3. 比较反转前后下标变化很容易得出 s[i] 的字符与 s[N - 1 - i] 的字符发生了交换的规律,因此我们可以得出如下双指针的解法:
  • 定义两个变量left,right分别指向第一个元素和最后一个元素;
  • 当 left < right 时,交换 left、right 指向的元素,同时 left 右移,right 左移;
  • 当 left >= right 时,反转完成;

    1. class Solution {
    2. public void reverseString(char[] s) {
    3. int length = s.length;
    4. for (int left = 0, right = length - 1; left < right; left ++, right --) {
    5. char temp = s[left];
    6. s[left] = s[right];
    7. s[right] = temp;
    8. }
    9. }
    10. }

    递归思想

    1. class Solution {
    2. public void reverseString(char[] s) {
    3. if (s == null || s.length == 0)
    4. return;
    5. reverseSubChar(s, 0, s.length - 1);
    6. }
    7. public void reverseSubChar(char[] s, int left, int right) {
    8. if (left >= right) {
    9. return;
    10. }
    11. s[left] ^= s[right];
    12. s[right] ^= s[left];
    13. s[left] ^= s[right];
    14. reverseSubChar(s, ++left, --right);
    15. }

    或者先递归再交换。
    这里递归方法使用的 left + 1,而不是 ++left,原因是,left + 1 不会改变 left 的值,在递归结束返回时,交换 left 和 right 的下标才正确。

    public void reverseSubChar(char[] s, int left, int right) {
      if (left >= right) {
          return;
      }
      reverseSubChar(s, left + 1, right - 1);
      s[left] ^= s[right];
      s[right] ^= s[left];
      s[left] ^= s[right];
    }
    

    知识点:交换的几种方式

    临时变量法

    public void swap(int a, int b) {
      int temp = a;
      a = b;
      b = temp;
    }
    

    运算法

    使用 +、-、*、/、位运算等操作进行交换

    public void swap(int a, int b) {
      a = a + b;
      b = a - b;
      a = a - b;
    }
    
    public void swap(int a, int b) {
      a = a - b;
      b = a + b;
      a = b - a;
    }
    
    public void swap(int a, int b) {
      a ^= b;
      b ^= a;
      a ^= b;
    }