字符串part02

今天学习了字符串的第二部分。

  1. 翻转字符串里的单词,先整体翻转,再局部翻转。注意移除空格和前头数组中移除元素类似。
  2. 右旋转,也是先整体再局部翻转。

4. 翻转字符串里的单词

题目:给定一个字符串,逐个翻转字符串中的每个单词。

示例 1:
输入: "the sky is blue"
输出: "blue is sky the"

示例 2:
输入: " hello world! "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

示例 3:
输入: "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。


若是无限制,split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加。但是限定只可以在原字符串里操作,所以解题思路如下:

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

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

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

a. 移除多余空格

总之属于移除元素,参考数组中移除元素的题目,采用快慢指针。其中6-8行的while负责循环完一个单词,fast指针碰到空格,就跳出while,到最外层的for中fast++,此时根据slow是不是0判断新开始的单词开头需不需要加空格。

void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
    int slow = 0;
    for (int i = 0; i < s.size(); ++i) { //
        if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
            if (slow != 0) s[slow++] = ' '; //除首之外的单词,前头都要加空格。
            while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
                s[slow++] = s[i++];
            }
        }
    }
    s.resize(slow); //slow的大小即为去除多余空格后的大小。
}

b. 字符串翻转

// 反转字符串s中左闭右闭的区间[start, end]
void reverse(string& s, int start, int end) {
    for (int i = start, j = end; i < j; i++, j--) {
        swap(s[i], s[j]);
    }
}

c.整体代码

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]);
        }
    }

    void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
        int slow = 0;
        for (int i = 0; i < s.size(); ++i) { //
            if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
                if (slow != 0) s[slow++] = ' '; 
                while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
                    s[slow++] = s[i++];
                }
            }
        }
        s.resize(slow); //slow的大小即为去除多余空格后的大小。
    }

    string reverseWords(string s) {
        removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
        reverse(s, 0, s.size() - 1);
        int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
        for (int i = 0; i <= s.size(); ++i) {
            if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
                reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
                start = i + 1; //更新下一个单词的开始下标start
            }
        }
        return s;
    }
};
  1. 翻转单词,注意这个思想,整体翻转+局部反转
  2. 移除多余空格=移除元素,使用双指针,只是注意对单词前加一个空格的处理方式

5. 右旋转字符

题目:字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。

例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"


类比上一题,可以想到使用多次翻转:

  1. 整体倒叙,把两段子串顺序颠倒
  2. 两个段子串里的的字符在倒叙,负负得正
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
    int n;
    string s;
    cin >> n;
    cin >> s;
    int len = s.size(); //获取长度
    reverse(s.begin(), s.end()); // 整体反转
    reverse(s.begin(), s.begin() + n); // 先反转前一段,长度n
    reverse(s.begin() + n, s.end()); // 再反转后一段
    cout << s << endl;

} 

字符串总结

基本可以分为以下几部分掌握:

1. 常用库函数

  1. std::string::length / std::string::size
  • 作用:返回字符串的长度(字符数)。

  • 用法

    std::string str = "Hello, World!";
    std::cout << "Length: " << str.length() << std::endl; // Output: Length: 13
    
  1. std::string::empty
  • 作用:检查字符串是否为空。

  • 用法

    std::string str = "";
    if (str.empty()) {
        std::cout << "The string is empty." << std::endl;
    }
    
  1. std::string::clear
  • 作用:清空字符串,使其变为空字符串。

  • 用法

    std::string str = "Hello, World!";
    str.clear();
    std::cout << "After clear: " << str << std::endl; // Output: After clear:
    
  1. std::string::append / std::string::operator+=
  • 作用:在字符串末尾追加字符或字符串。

  • 用法

    std::string str = "Hello";
    str.append(", World!");
    std::cout << str << std::endl; // Output: Hello, World!
    
    str += " How are you?";
    std::cout << str << std::endl; // Output: Hello, World! How are you?
    
  1. std::string::substr
  • 作用:返回字符串中指定位置的子字符串。

  • 用法

    std::string str = "Hello, World!";
    std::string sub = str.substr(7, 5); // 从位置7开始,截取5个字符
    std::cout << "Substring: " << sub << std::endl; // Output: Substring: World
    
  1. std::string::find
  • 作用:在字符串中查找子字符串或字符,返回首次出现的位置索引。如果未找到,则返回 std::string::npos

  • 用法

    std::string str = "Hello, World!";
    size_t pos = str.find("World");
    if (pos != std::string::npos) {
        std::cout << "'World' found at position: " << pos << std::endl; // Output: 'World' found at position: 7
    }
    
  1. std::string::replace
  • 作用:用新的子字符串替换字符串中的部分内容。

  • 用法

    std::string str = "Hello, World!";
    str.replace(7, 5, "C++"); // 从位置7开始,替换5个字符为 "C++"
    std::cout << "After replace: " << str << std::endl; // Output: After replace: Hello, C++!
    
  1. std::string::compare
  • 作用:比较两个字符串的大小。

  • 用法

    std::string str1 = "Apple";
    std::string str2 = "Banana";
    int result = str1.compare(str2);
    if (result < 0) {
        std::cout << "str1 is less than str2" << std::endl;
    } else if (result > 0) {
        std::cout << "str1 is greater than str2" << std::endl;
    } else {
        std::cout << "str1 is equal to str2" << std::endl;
    }
    
  1. std::string::erase
  • 作用:删除字符串中的部分内容。

  • 用法

    std::string str = "Hello, World!";
    str.erase(5, 7); // 从位置5开始,删除7个字符
    std::cout << "After erase: " << str << std::endl; // Output: After erase: Hello!
    
  1. std::string::insert
  • 作用:在字符串的指定位置插入子字符串。

  • 用法

    std::string str = "Hello!";
    str.insert(5, ", World"); // 在位置5插入 ", World"
    std::cout << "After insert: " << str << std::endl; // Output: After insert: Hello, World!
    
  1. std::string::c_str
  • 作用:返回一个指向 C 风格字符串的指针(const char*)。

  • 用法

    std::string str = "Hello, World!";
    const char* cstr = str.c_str();
    std::cout << "C-style string: " << cstr << std::endl; // Output: C-style string: Hello, World!
    
  1. std::string::at
  • 作用:返回字符串中指定位置的字符,并进行边界检查。

  • 用法

    std::string str = "Hello, World!";
    char ch = str.at(1); // 获取位置1处的字符
    std::cout << "Character at index 1: " << ch << std::endl; // Output: Character at index 1: e
    
  1. std::string::resize
  • 作用:调整字符串的大小,可以增加或减少长度。

  • 用法

    std::string str = "Hello, World!";
    str.resize(5);
    std::cout << "After resize: " << str << std::endl; // Output: After resize: Hello
    
    str.resize(10, '!');
    std::cout << "After resize with fill: " << str << std::endl; // Output: After resize with fill: Hello!!!!!
    
  1. std::string::push_back / std::string::pop_back
  • 作用:在字符串末尾添加或删除一个字符。

  • 用法

    std::string str = "Hello";
    str.push_back('!');
    std::cout << "After push_back: " << str << std::endl; // Output: After push_back: Hello!
    
    str.pop_back();
    std::cout << "After pop_back: " << str << std::endl; // Output: After pop_back: Hello
    

2. 双指针解决问题

移除元素、反转链表/字符串、替换元素,这三样都需要双指针。

3. 翻转问题

一段一段有规律的精细翻转,考虑再for循环上做文章;一般的翻转考虑局部+整体的结合。

4. KMP经典算法

需要熟练掌握。

今日古诗

唐多令·芦叶满汀洲

芦叶满汀洲,寒沙带浅流。二十年重过南楼。柳下系船犹未稳,能几日,又中秋。
黄鹤断矶头,故人今在否?旧江山浑是新愁。欲买桂花同载酒,终不似,少年游。

《唐多令·芦叶满汀洲》是一首登临名作,词人借重过武昌南楼之机,感慨时事,抒写昔是今非和怀才不遇的思想感情。词的上阕抒发对时光流逝、物是人非的世道沧桑的强烈感受;下阕以疏俊之笔抒写故友凋零、山河破碎、好梦不再的今昔感概。全词怀旧抚今,情调哀伤,其词意凄怆清越,委婉含蓄,耐人寻味。

posted @ 2024-08-09 11:51  YueHuai  阅读(326)  评论(0编辑  收藏  举报