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 → 反转的终点的下一个位置(不包含)
相关推荐
LeetCode天天刷3 小时前
【软件认证】比特翻转【滑动窗口】
算法
源代码•宸3 小时前
Leetcode—1123. 最深叶节点的最近公共祖先【中等】
经验分享·算法·leetcode·职场和发展·golang·dfs
liulilittle3 小时前
LIBTCPIP 技术探秘(tun2sys-socket)
开发语言·网络·c++·信息与通信·通信·tun
yyy(十一月限定版)3 小时前
c++(3)类和对象(中)
java·开发语言·c++
s砚山s3 小时前
代码随想录刷题——二叉树篇(十三)
数据结构·算法
alphaTao3 小时前
LeetCode 每日一题 2026/1/5-2026/1/11
算法·leetcode
山上三树3 小时前
详细介绍 C 语言中的 #define 宏定义
c语言·开发语言·算法
DYS_房东的猫3 小时前
写出第一个程序
c++
ulias2123 小时前
AVL树的实现
开发语言·数据结构·c++·windows
黎雁·泠崖3 小时前
二叉树知识体系全梳理:从基础到进阶一站式通关
c语言·数据结构·leetcode