在问 · 算法题解

541. 反转字符串 II

题目描述

输入字符串 s 和正整数 k。从开头起,把 s 依次切成长度为 2k 的若干段,最后一段可能不足 2k。

对每一段,只把其中前 k 个字符的顺序颠倒,后面的字符保持不动。若最后一段长度不到 k,就把这一段全部颠倒;若长度在 k 与 2k 之间,仍只颠倒前 k 个。

返回处理后的字符串。

示例 1
输入:s = "abcdefg", k = 2
输出:"bacdfeg"

解释:第一段 "abcd" 变为 "bacd",剩下的 "efg" 不足 2k,只颠倒前 2 个得到 "feg"。

示例 2
输入:s = "abcd", k = 2
输出:"bacd"

解释:只有一段 "abcd",颠倒前 2 个字符得到 "bacd"。

数据范围

  • 1 <= s.length <= 10^4
  • s 只包含小写英文字母。
  • 1 <= k <= 10^4

解题思路

让 start 以 2k 为步长遍历 0, 2k, 4k, …,每个 start 都是一段的开头。要反转的区间是 [start, min(start + k, n) - 1]:取 min 正好把两种尾部情况统一起来——剩余不足 k 个时反转到末尾,否则只反转 k 个。每个区间内用左右双指针交换,和普通的反转字符串完全一样。

为什么正确

处理到某一段时,前面各段都已是最终结果;段内 t[start..i) 和 t(j..end] 已就位,且 i + j 始终等于区间两端之和。

复杂度分析

时间 O(n),每个字符最多被交换一次;额外空间 O(n),用于字符列表。

易错点

右端要取 min(start + k, n) - 1,直接用 start + k - 1 在最后一段可能越界;步长是 2k 而不是 k,否则会把不该反转的后 k 个字符也反转了。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        t = list(s)
        for start in range(0, len(t), 2 * k):
            i = start
            j = min(start + k, len(t)) - 1
            while i < j:
                t[i], t[j] = t[j], t[i]
                i += 1
                j -= 1
        return ''.join(t)

载入编辑器,自己跑一遍 →

双指针 专题的其他题目

查看 双指针 全部题目 →