C++ LeetCode 力扣刷题 541. 反转字符串 II

一、题目

541. 反转字符串 II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

复制代码
输入:s = "abcdefg", k = 2
输出:"bacdfeg"

示例 2:

复制代码
输入:s = "abcd", k = 2
输出:"bacd"

2题目思路

解决这道题的核心是按照规则分段处理字符串,每段长度为 2k,并对每段的前 k 个字符进行反转。具体思路如下:

1. 明确处理规则

题目要求按 2k 个字符为一组分段处理,每段的处理逻辑:

  • 若段内字符数 ≥ k :反转前 k 个字符,剩余字符不变(即使超过 k 但不足 2k)。
  • 若段内字符数 < k:将剩余字符全部反转。

2. 确定分段方式

  • 从字符串开头(索引 0)开始,每次跳过 2k 个字符,处理下一段(即段的起始索引依次为 0, 2k, 4k, ...)。
  • 对每一段,先确定需要反转的范围:
    • 反转的起点:当前段的起始索引 i
    • 反转的终点:i + k - 1(前 k 个字符的最后一个),但如果剩余字符不足 k 个,终点就取字符串的最后一个索引(n-1n 为字符串长度)。

3. 实现反转操作

对每个确定的反转范围 [起点, 终点],通过双指针法反转字符:

  • 左指针从起点开始,右指针从终点开始。
  • 交换左右指针指向的字符,然后左指针右移、右指针左移,直到两指针相遇(左指针 ≥ 右指针)。

4. 流程总结

  1. 计算字符串长度 n,初始化当前段的起始索引 i = 0
  2. 循环处理每一段(直到 i 超出字符串长度):
    • 计算当前段反转的终点 end = min(i + k - 1, n - 1)(确保不越界)。
    • 用双指针反转 [i, end] 范围内的字符。
    • i 增加 2k,进入下一段。
  3. 返回处理后的字符串。

举例理解(以 s = "abcdefg", k = 2 为例)

  • 字符串长度 n = 7,分段步长 2k = 4
  • 第一段 i = 0
    • 终点 end = min(0 + 2 - 1, 6) = 1,反转 [0,1]s 变为 "bacdefg"
    • i 更新为 0 + 4 = 4
  • 第二段 i = 4
    • 终点 end = min(4 + 2 - 1, 6) = 5,反转 [4,5]s 变为 "bacdfeg"
    • i 更新为 4 + 4 = 8,超出 n=7,循环结束。
  • 最终结果:"bacdfeg",符合示例。

通过这种分段处理 + 双指针反转的思路,能高效满足题目要求,时间复杂度为 O(n)(每个字符最多被反转一次),空间复杂度为 O(1)(仅用常数空间)。

三、代码

1.while方法

cpp 复制代码
class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.size(); // 先获取字符串长度,避免重复计算
        int i = 0;
        
        while (i < n) {
            // 1. 计算当前需要反转的终点(确保不超过字符串末尾)
            int end = i + k - 1;
            if (end >= n) { // 如果终点越界,修正为最后一个字符的索引
                end = n - 1;
            }
            
            // 2. 反转[i, end]区间的字符(用双指针交换,确保left < right)
            int left = i;
            int right = end;
            while (left < right) { // 只有当left在right左边时才交换
                swap(s[left], s[right]);
                left++;
                right--;
            }
            
            // 3. 移动到下一个2k区间的起点
            i += 2 * k;
        }
        
        return s;
    }
};

2.for方法

cpp 复制代码
class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.size();
        // 每次跳过2k个字符,处理一个区间
        for (int i = 0; i < n; i += 2 * k) {
            // 确定反转的终点:取i+k-1和n-1中的较小值(避免越界)
            int end = min(i + k - 1, n - 1);
            // 反转从i到end的字符
            reverse(s.begin() + i, s.begin() + end + 1);
        }
        return s;
    }
};

3.哪个更好?

在本题场景下,for 循环更合适,原因如下:

  1. 逻辑匹配度高 :本题需要按固定步长 2k 遍历(从 0 开始,每次加 2k,直到超出字符串长度),for 循环的语法结构(init; cond; step)完美契合这种 "已知起点、终点、步长" 的遍历需求。
  2. 代码更紧凑:将循环变量初始化、终止条件、步长更新集中在一行,减少了分散的代码片段,可读性更高(他人一眼就能理解遍历规则)。
  3. 不易出错while 循环需要手动在循环内更新步长(i += 2k),若遗漏则会导致死循环;而 for 循环的步长写在固定位置,更不容易疏忽。

4.总结

  • for 循环适合固定步长、已知循环范围的场景(如本题),代码更简洁,意图更明确。
  • while 循环适合条件复杂、循环次数不确定的场景(如根据动态输入决定是否继续循环)。

四、reverse 函数解释

reverse(s.begin() + i, s.begin() + end + 1) 中的两个参数是 迭代器(iterator) ,用于指定 reverse 函数需要反转的字符范围。这两个迭代器的计算方式和含义如下:

1.先理解 reverse 函数的特性

C++ 标准库的 reverse 函数用于反转一个容器中 [first, last) 区间内的元素(左闭右开区间),即:

  • 包含 first 指向的元素
  • 不包含 last 指向的元素
  • 最终会反转 firstlast-1 之间的所有元素

2.两个参数的含义

假设字符串 s 的字符索引为 0, 1, 2, ..., n-1n 是字符串长度),我们需要反转 从索引 iend 的字符 (包含 iend)。

此时:

  • 第一个参数 s.begin() + is.begin() 是字符串的起始迭代器(指向索引 0),+i 后指向索引 i 的位置,即反转的起始位置(包含该位置)。

  • 第二个参数 s.begin() + end + 1s.begin() + end 指向索引 end 的位置,+1 后指向索引 end+1 的位置,即反转的结束位置的下一个位置(不包含该位置)。

这样,[s.begin() + i, s.begin() + end + 1) 就刚好覆盖了 索引 iend 的所有字符 ,符合 reverse 函数左闭右开的要求。

举例说明

假设字符串 s = "abcdef"(索引 0-5),需要反转 i=1end=3 的字符(即 b, c, d):

  • s.begin() + 1 指向索引 1(字符 b
  • s.begin() + 3 + 1 = s.begin() + 4 指向索引 4(字符 e
  • reverse 函数会反转 [1,4) 区间,即索引 1,2,3 的字符,结果为 adcbefb,c,d 反转为 d,c,b)。

总结

reverse 函数的参数是通过 起始迭代器 + 偏移量 计算的,目的是精准指定需要反转的范围:

  • 第一个参数:s.begin() + i → 反转的起点(包含)
  • 第二个参数:s.begin() + end + 1 → 反转的终点的下一个位置(不包含)
相关推荐
小白程序员成长日记44 分钟前
2025.11.29 力扣每日一题
数据结构·算法·leetcode
在黎明的反思2 小时前
进程通信之消息队列(IPC)
算法
老鱼说AI2 小时前
算法基础教学第一步:数据结构
数据结构·python·算法
极地星光2 小时前
C++链式调用设计:打造优雅流式API
服务器·网络·c++
Jing_Rainbow2 小时前
【LeetCode Hot100 刷题日记(19/100)】54. 螺旋矩阵 —— 数组、矩阵、模拟、双指针、层序遍历🌀
算法·面试·程序员
小陈要努力3 小时前
Visual Studio 开发环境配置指南
c++·opengl
程序猿本员3 小时前
5. 实现
c++
Bona Sun3 小时前
单片机手搓掌上游戏机(十五)—pico运行fc模拟器之编译环境
c语言·c++·单片机·游戏机
地平线开发者3 小时前
征程 6 | linear 高精度输出配置方式
算法·自动驾驶
小尧嵌入式4 小时前
C++基础语法总结
开发语言·c++·stm32·单片机·嵌入式硬件·算法