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 → 反转的终点的下一个位置(不包含)
相关推荐
报错小能手2 小时前
C++笔记——STL list
c++·笔记
T.Ree.2 小时前
cpp_list
开发语言·数据结构·c++·list
laocooon5238578862 小时前
C++ 图片加背景音乐的处理
开发语言·c++
apocelipes2 小时前
POSIX兼容系统上read和write系统调用的行为总结
linux·c语言·c++·python·golang·linux编程
暴风鱼划水2 小时前
算法题(Python)数组篇 | 6.区间和
python·算法·数组·区间和
No0d1es2 小时前
2025年第十六届蓝桥杯青少组省赛 C++编程 中级组真题
c++·青少年编程·蓝桥杯·省赛
千禧皓月2 小时前
【C++】基于C++的RPC分布式网络通信框架(二)
c++·分布式·rpc
zl_vslam3 小时前
SLAM中的非线性优-3D图优化之轴角在Opencv-PNP中的应用(一)
前端·人工智能·算法·计算机视觉·slam se2 非线性优化
是苏浙3 小时前
零基础入门C语言之C语言实现数据结构之顺序表应用
c语言·数据结构·算法