题目
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须**原地修改输入数组**、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入: s = ["h","e","l","l","o"]
输出: ["o","l","l","e","h"]
示例 2:
输入: s = ["H","a","n","n","a","h"]
输出: ["h","a","n","n","a","H"]
提示:
1 <= s.length <= 105s[i]都是 ASCII 码表中的可打印字符
解题思路🙋🏻 ♀️
输入数组是 ["H","a","n","n","a","h"]。
初始状态,left 指向第一个元素,right 指向最后一个元素:
s: "H" -> "a" -> "n" -> "n" -> "a" -> "h"
^ ^
leftPointer rightPointer
第一次迭代,交换 leftPointer 和 rightPointer 指向的元素,然后 leftPointer 向右移动一位,rightPointer 向左移动一位:
s: "h" -> "a" -> "n" -> "n" -> "a" -> "H"
^ ^
leftPointer rightPointer
第二次迭代,交换 leftPointer 和 rightPointer 指向的元素,然后 leftPointer 向右移动一位,rightPointer 向左移动一位:
s: "h" -> "a" -> "n" -> "n" -> "a" -> "H"
^ ^
leftPointer rightPointer
第三次迭代,leftPointer 和 rightPointer 指向的元素都是 "n",所以不用交换,直接将 leftPointer 向右移动一位,rightPointer 向左移动一位:
s: "h" -> "a" -> "n" -> "n" -> "a" -> "H"
^
leftPointer, rightPointer
此时 leftPointer 已经不小于 rightPointer,所以循环结束。最终的结果就是 ["h","a","n","n","a","H"],这就是字符串的反转结果。
边界思考🤔
这个算法的边界条件主要是字符数组的长度。如果数组为空或只包含一个元素,那么我们不需要做任何处理,直接返回即可。
特殊处理的情况主要是数组长度为奇数时,中间的元素不需要交换。
以下是对应的图示:
-
当数组为空时,我们直接返回:
s: -
当数组只包含一个元素时,我们也直接返回:
s: "a"
代码
class Solution {
// 函数开始,参数是一个字符数组,inout 表示这个数组可以在函数内部被修改
func reverseString(_ s: inout [Character]) {
// 如果数组的元素个数小于等于1,那么直接返回,因为没有必要进行移动
if s.count <= 1 {
return
}
// 初始化两个指针,left 指向数组的开始,right 指向数组的结尾
var left = 0
var right = s.count - 1
// 当 left 指针小于 right 指针时,执行循环
while left < right {
// 交换 left 和 right 指针指向的字符
s.swapAt(left,right)
// 将 left 指针向右移动一位,将 right 指针向左移动一位
left += 1
right -= 1
}
}
}
时空复杂度分析
时间复杂度 O(n)
通过两个指针来交换字符数组的元素,从而达到反转字符串的目的。因为只是在原数组上进行操作,没有使用额外的数组或者字符串,所以空间复杂度是 O(1)。