day08,day09——字符串的操作

344-翻转字符串

这个题比较简单,主要考察实现一下reverse函数。

344. 反转字符串 - 力扣(LeetCode)

具体可以通过使用双指针left和right来实现,指向两端,同时交换数据然后移动。

时间复杂度为O(n),空间复杂度为O(1)。具体代码就不给出来啦,下面的541题中会用到翻转的操作,可以看一下下面541题的实现代码。

541-翻转字符串Ⅱ

541. 反转字符串 II - 力扣(LeetCode)

题目比较简单,这里的rever函数实现就是双指针来实现字符串指定范围的翻转

class Solution {
public:
    void rever(string &s, int left, int right){
        while(left<right){
            char temp;
            temp=s[left];
            s[left]=s[right];
            s[right]=temp;
            left++;
            right--;
        }
        cout<<s<<endl;
    }
    string reverseStr(string s, int k) {
        int num=0;
        while(num<=s.size()){
            if(num+k<=s.size()){
                int left=num, right=num+k-1;
                rever(s, left, right);
                num+=2*k;
                continue;
            }

            if(num+k>=s.size()){
                int left=num, right=s.size()-1;
                rever(s, left, right);
                num+=2*k;
                continue;
            }

        }
        return s;
        
    }
};

替换数字

替换数字 | 代码随想录

比较简单,不多赘述,从前向后加就行,用一个额外的string来保存结果,然后采用双指针的思想,直接从前往后遍历就可以,不需要卡哥那样从后往前。

#include <iostream>
#include <string>

std::string replaceDigits(const std::string& s) {
    std::string result;
    for (char c : s) {
        if (isdigit(c)) {
            result += "number";
        } else {
            result += c;
        }
    }
    return result;
}

int main() {
    std::string s;
    std::cout << "请输入字符串: ";
    std::cin >> s;
    std::cout << "转换后的字符串: " << replaceDigits(s) << std::endl;
    return 0;
}

151.翻转字符串里的单词

题目描述

题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)

给你一个字符串 s ,请你反转字符串中 单词 的顺序

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格尾随空格或者单词间的多个空格

返回的结果字符串中,需要去除所有的前导空格,需要去除所有的尾随空格,且单词间应当仅保留单个空格分隔

示例:

我的代码思路:

  1. 去除尾部空格:使用 while 循环将 right 指针移动到第一个非空格字符。

     
  2. 寻找单词:内部 while 循环,将 left 指针移动到单词的开始位置。

     
  3. 提取单词:使用 s.substr(left + 1, right - left) 提取单词,并添加到 result 字符串。当然这个substr的逻辑我们也可以手动实现。

     
  4. 跳过单词之间的空格:在提取单词后,移动left指针,跳过单词之间的空格,直到left指向一个字符,然后让right=left,重复第二步寻找单词步骤。

     
  5. 去除尾部空格:在返回最终的字符串之前,检查字符串是否为空,如果不为空,删除字符串的最后一个字符(空格)。

注意:这里的第五步删除的空格并不是我们的串首空格,串首空格在第四步left指针已经忽略了,这里的空格是:

  • 添加空格的逻辑: 在代码的 result += s.substr(left + 1, right - left) + " "; 这一行,每次提取一个单词后,都会在 result 字符串的末尾添加一个空格
  • 最后一个单词: 当逆序遍历到字符串的第一个单词时,也会执行上述添加空格的逻辑。因此,无论输入字符串的内容如何,最终的 result 字符串的末尾都会多出一个空格。

我的代码实现:

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

std::string reverseWords(std::string s) {
    int n = s.size();
    int right = n - 1;
    std::string result = "";

    // 去除尾部空格
    while (right >= 0 && s[right] == ' ') {
        right--;
    }
    int left = right;

    while (right >= 0) {
        // 寻找单词的开始
        while (left >= 0 && s[left] != ' ') {
            left--;
        }

        // 添加单词到结果字符串
        result += s.substr(left + 1, right - left) + " ";

        // 跳过单词之间的空格
        while (left >= 0 && s[left] == ' ') {
            left--;
        }
        right = left;
    }
    //去除尾部多余的空格
    if (!result.empty()) {
        result.pop_back();//移除多加的一个空格
    }
    return result;
}

原地操作代码思路:

这道题推可以尝试使用 O(1) 额外空间复杂度的 原地 解法,一开始我确实想不出来,让我们看看卡哥是如何做的。

想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒序了,那么再把单词反转一下,单词不就正过来了。

所以解题思路如下:

  • 移除多余空格
  • 将整个字符串反转
  • 将每个单词反转

举个例子,源字符串为:"the sky is blue "

  • 移除多余空格 : "the sky is blue"
  • 字符串反转:"eulb si yks eht"
  • 单词反转:"blue is sky the"

这样我们就完成了翻转字符串里的单词。

代码实现:

void reverseWords(string &s) {
    // 1. 去除多余空格
    int slow = 0, fast = 0;
    
    // 跳过前导空格
    while (fast < str.size() && str[fast] == ' ') fast++;

    //处理单词和间隔
    while (fast < str.size()) {
        if (str[fast] != ' ') {  
            str[slow++] = str[fast++];
        } else {  
            // 先写入一个空格
            if (slow > 0) str[slow++] = ' ';
            // 跳过连续空格
            while (fast < str.size() && str[fast] == ' ') fast++;
        }
    }
    //  检查是否有误加的尾部空格,如果有的话就去掉尾部空格
    if (str[slow - 1] == ' ') 
        slow--;

    str.resize(slow);  // 调整字符串大小

    // 2. 反转整个字符串
    reverse(s.begin(), s.end());

    // 3. 反转每个单词
    int start = 0, end = 0;
    while (end < s.size()) {
        if (s[end] == ' ') {
            reverse(s.begin() + start, s.begin() + end);
            start = end + 1;
        }
        end++;
    }
    reverse(s.begin() + start, s.end()); // 反转最后一个单词
}

双指针去除空格

在这个代码中,我觉得最需要我们来学习的点是这里的去除空格的操作,这里去除空格如果采用简单的remove操作的话,时间复杂度将会很大,因为对字符串的remove操作非常昂贵,去除这里的空格之后,后面整体的字符串都需要发生移动。一次remove的操作代价是O(N),多次操作的代价就是O(N^2),所以显然不能采用库函数remove。

这里去除空格的操作可以用到我们的老朋友:双指针

思路大概就是快慢指针,

  • 快指针 (fast) 用于遍历原始字符串,筛选出有效的字符。
  • 慢指针 (slow) 用于记录新字符串的写入位置。

但是这里操作肯定没有这么简单啦!如果是将全部空格删去的话操作很简单,但这里对于两个相邻字符串之间的空格要保留一个,不能完全删除!!!

这里本质上还是双指针只不过逻辑判断处理要麻烦一点。

void remove_space(string& str){
    int slow = 0, fast = 0;
    
    // 1. 跳过前导空格
    while (fast < str.size() && str[fast] == ' ') fast++;

    // 2. 处理单词和间隔
    while (fast < str.size()) {
        if (str[fast] != ' ') {  
            str[slow++] = str[fast++];
        } else {  
            // 先写入一个空格
            if (slow > 0) str[slow++] = ' ';
            // 跳过连续空格
            while (fast < str.size() && str[fast] == ' ') fast++;
        }
    }

    // 3. 检查是否有误加的尾部空格,如果有的话就去掉尾部空格
    if (str[slow - 1] == ' ') 
        slow--;

    str.resize(slow);  // 调整字符串大小

    // **测试输出**
    cout << str << endl;
}

KMP算法

用于在一个文本字符串(text)中查找一个模式字符串(pattern)的出现。KMP 算法避免了不必要的回溯,从而提高了匹配效率。

时间复杂度为 O(m + n),其中 n 是文本字符串的长度,m 是模式字符串的长度。

KMP暂时看不懂,虽然能会算,但是理解不了原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值