代码随想录--字符串--反转字符串II

题目

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

如果剩余字符少于 k 个,则将剩余字符全部反转。

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

示例:

输入: s = “abcdefg”, k = 2
输出: “bacdfeg”

思路

这道题目其实也是模拟,实现题目中规定的反转规则就可以了。

一些同学可能为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。

其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。

因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。

所以当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。

性能如下:
在这里插入图片描述

那么这里具体反转的逻辑我们要不要使用库函数呢,其实用不用都可以,使用reverse来实现反转也没毛病,毕竟不是解题关键部分。

使用C++库函数reverse的版本如下:

class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 1. 每隔 2k 个字符的前 k 个字符进行反转
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= s.size()) {
reverse(s.begin() + i, s.begin() + i + k );
} else {
// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
reverse(s.begin() + i, s.end());
}
}
return s;
}
};

时间复杂度: O(n)
空间复杂度: O(1)

下面我实现的reverse函数区间是左闭右闭区间,代码如下:

class Solution {
public:
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j–) {
swap(s[i], s[j]);
}
}
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 1. 每隔 2k 个字符的前 k 个字符进行反转
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= s.size()) {
reverse(s, i, i + k - 1);
continue;
}
// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
reverse(s, i, s.size() - 1);
}
return s;
}
};

时间复杂度: O(n)
空间复杂度: O(1)或O(n), 取决于使用的语言中字符串是否可以修改

另一种思路的解法

class Solution {
public:
string reverseStr(string s, int k) {
int n = s.size(),pos = 0;
while(pos < n){
//剩余字符串大于等于k的情况
if(pos + k < n) reverse(s.begin() + pos, s.begin() + pos + k);
//剩余字符串不足k的情况
else reverse(s.begin() + pos,s.end());
pos += 2 * k;
}
return s;
}
};

时间复杂度: O(n)
空间复杂度: O(1)

Java

//解法一
class Solution {
public String reverseStr(String s, int k) {
StringBuffer res = new StringBuffer();
//StringBuffer 类是用来表示可变字符串的,也就是说,创建后字符串的内容是可以修改的。这与 String 类不同,String 类是不可变的,一旦创建就不能更改,任何修改都会创建一个新的对象。

    int length = s.length();
    int start = 0;
    while (start < length) {
        // 找到k处和2k处
        StringBuffer temp = new StringBuffer();
        // 与length进行判断,如果大于length了,那就将其置为length
        int firstK = (start + k > length) ? length : start + k;
        int secondK = (start + (2 * k) > length) ? length : start + (2 * k);

        //无论start所处位置,至少会反转一次
        temp.append(s.substring(start, firstK));
        res.append(temp.reverse());

s.substring(start, firstK):这是调用了 String 类的 substring 方法,用于从字符串 s 中提取子字符串。substring 方法接收两个参数,分别是子字符串的开始索引(包含)和结束索引(不包含)。在这个例子中,start 和 firstK 都是整数,代表了子字符串在原字符串 s 中的起始和结束位置。因此,s.substring(start, firstK) 返回的是从 s 的第 start 个字符开始,到第 firstK - 1 个字符为止的子字符串。

temp.append(s.substring(start, firstK)) 的作用是将从 s 中提取的子字符串追加到 temp 对象的末尾。

        // 如果firstK到secondK之间有元素,这些元素直接放入res里即可。
        if (firstK < secondK) { //此时剩余长度一定大于k。
            res.append(s.substring(firstK, secondK));
        }
        start += (2 * k);
    }
    return res.toString();
}

}

//解法二(似乎更容易理解点)
//题目的意思其实概括为 每隔2k个反转前k个,尾数不够k个时候全部反转
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0; i < ch.length; i += 2 * k){
int start = i;
//这里是判断尾数够不够k个来取决end指针的位置
int end = Math.min(ch.length - 1, start + k - 1);
//用异或运算反转
while(start < end){
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end–;
}
}
return new String(ch);
}
}

// 解法二还可以用temp来交换数值,会的人更多些
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0;i < ch.length;i += 2 * k){
int start = i;
// 判断尾数够不够k个来取决end指针的位置
int end = Math.min(ch.length - 1,start + k - 1);
while(start < end){

            char temp = ch[start];
            ch[start] = ch[end];
            ch[end] = temp;

            start++;
            end--;
        }
    }
    return new String(ch);
}

}

// 解法3
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
// 1. 每隔 2k 个字符的前 k 个字符进行反转
for (int i = 0; i< ch.length; i += 2 * k) {
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= ch.length) {
reverse(ch, i, i + k -1);
continue;
}
// 3. 剩余字符少于 k 个,则将剩余字符全部反转
reverse(ch, i, ch.length - 1);
}
return new String(ch);

}
// 定义翻转函数
public void reverse(char[] ch, int i, int j) {
for (; i < j; i++, j--) {
    char temp  = ch[i];
    ch[i] = ch[j];
    ch[j] = temp;
}

}

}

  • 31
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值