算法训练Day8| LeetCode344. 反转字符串(双指针);541. 反转字符串II(模拟);54.替换数字

344. 反转字符串

题目来源:344. 反转字符串 - 力扣(LeetCode)

文章来源:代码随想录

这道题用首尾双指针就行,个人代码如下:

class Solution {
public:
    void reverseString(vector<char>& s) {
        //定义left和right指针
        int left = 0,right = s.size()-1;
        char temp;
        while(left<right){
            temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            left++;right--;
        }
        return;   
    }
};

这道题还有一个原地交换的操作

s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];

这个原地操作的原理我去问deepseek,它的回答如下:

这段代码通过三次异或(XOR)操作实现了元素交换,其核心原理基于异或运算的三个关键性质:

  1. 自反性a ^ a = 0(任何数与自身异或结果为0)。

  2. 恒等性a ^ 0 = a(任何数与0异或结果不变)。

  3. 交换律与结合律:异或操作顺序不影响结果。

分步解析(假设初始时 s[i] = as[j] = b):

  1. 第一步s[i] ^= s[j]
    等价于 s[i] = a ^ b。此时 s[i] 存储了 a 和 b 的异或结果,而 s[j] 仍为 b

  2. 第二步s[j] ^= s[i]
    等价于 s[j] = b ^ (a ^ b)。根据交换律和自反性,这简化为 a(因为 b ^ b = 00 ^ a = a)。此时 s[j] 变为 as[i] 仍为 a ^ b

  3. 第三步s[i] ^= s[j]
    等价于 s[i] = (a ^ b) ^ a。同样利用交换律和自反性,这简化为 ba ^ a = 00 ^ b = b)。此时 s[i] 变为 bs[j] 为 a,完成交换。

541. 反转字符串II

题目链接:541. 反转字符串 II - 力扣(LeetCode)

这道题是模拟,直接实现即可,个人代码如下:

class Solution {
public:
    string reverseStr(string s, int k) {
        //定义反转那一段的起点和终点下标
        int begin = 0,end,length = s.length(),i,j;
        //如果这一整段能够替换,正常设置end
        if(begin+k-1<length){
            end = begin+k-1;
        }
        //如果不够一整段替换,设置end为字符串末尾
        else{
            end = length-1;
        }
        //当反转下标为最后一个元素也不用反转了
        while(begin<length-1){
            //开始进行替换操作
            i = begin;
            j = end;
            while(i<j){
                s[i] ^= s[j];
                s[j] ^= s[i];
                s[i] ^= s[j];
                i++;j--;
            }
            //替换完之后要更新begin,end
            if(begin+2*k<length-1){
                begin += 2*k;
            }
            else{
                break;
            }
            if(begin+k-1<length){
                end = begin+k-1;
            }
            //如果不够一整段替换,设置end为字符串末尾
            else{
                end = length-1;
            }
        }
        return s;
    }
};

54.替换数字

题目链接:54. 替换数字(第八期模拟笔试)

参考文章:替换数字 | 代码随想录

图片来源于参考文章。

这道题直观来讲我是开辟额外数组来完成的。空间复杂度为O(n)时间复杂度为O(n),个人代码如下:

#include <bits/stdc++.h>
using namespace std;

int main(){
    string str_a,str_b;
    int i;
    getline(cin,str_a);
    //开始遍历,放入str_b中
    for(i = 0;i<str_a.length();i++){
        //如果是小写字母,就直接赋值给str_b
        if(str_a[i]>='a'&&str_a[i]<='z'){
            str_b.push_back(str_a[i]);
        }
        else{
            str_b += "number";
        }
    }
    for(int j = 0;j<str_b.length();j++){
        cout<<str_b[j];
    }
    return 0;
}

但卡哥给出了空间复杂度更低的做法的原理和图解,卡哥文章已经写得很详细了,我这里就不再赘述。我只想强调文章的一个结论。

其实很多数组填充类的问题,其做法都是先预先给数组扩容到填充后的大小,然后再从后向前进行操作。

这么做有两个好处:

  1. 不用申请新数组。
  2. 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。

卡哥参考代码如下:

#include <iostream>
using namespace std;
int main() {
    string s;
    while (cin >> s) {
        int sOldIndex = s.size() - 1;
        int count = 0; // 统计数字的个数
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= '0' && s[i] <= '9') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是将每个数字替换成"number"之后的大小
        s.resize(s.size() + count * 5);
        int sNewIndex = s.size() - 1;
        // 从后往前将数字替换为"number"
        while (sOldIndex >= 0) {
            if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
                s[sNewIndex--] = 'r';
                s[sNewIndex--] = 'e';
                s[sNewIndex--] = 'b';
                s[sNewIndex--] = 'm';
                s[sNewIndex--] = 'u';
                s[sNewIndex--] = 'n';
            } else {
                s[sNewIndex--] = s[sOldIndex];
            }
            sOldIndex--;
        }
        cout << s << endl;       
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值