代码随想录算法训练营第九天 | 151.翻转字符串里的单词,卡码网:55.右旋转字符串,28. 实现 strStr(),459.重复的子字符串,字符串总结,双指针总结

训练营第九天继续打卡,今天的内容还是做了挺久的。第1题删除多余空格的操作想了比较久,然后看了下KMP还是没很懂,后面再看。


151.翻转字符串中的单词

题目链接

解题过程

  • 若不用库函数,全部自己实现功能,则可以分三步:第一步删掉多余空格,这一步可以参考力扣27题(移除元素);第二步反转所有字符串;第三步逐个单词反转
  • 这次把删除多余空格实现出来了,但是后面两步又没写出来,这题还是比较难写的,后面还会再来做这一题

知识点

  • 使用erase移除空格的时间复杂度为O(n^2),所以采用双指针移除元素
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

整体代码

class Solution {
public:
    void deleteSpace(string& s) {
        int slow = 0;
        for (int fast = 0; fast < s.size(); fast++) {
            if (s[fast] != ' ') {
                if (slow != 0) s[slow++] = ' ';
                while (fast < s.size() && s[fast] != ' ') {
                    s[slow++] = s[fast++];
                }
            }
        }
        s.resize(slow);
    }
    void myReverse(string& s, int leftIndex, int rightIndex) {
        while (leftIndex < rightIndex) swap(s[leftIndex++], s[rightIndex--]);
    }
    string reverseWords(string s) {
        deleteSpace(s);
        myReverse(s, 0, s.size() - 1);
        int start = 0;
        for (int i = 0; i <= s.size(); i++) {
            if (i == s.size() || s[i] == ' ') {
                myReverse(s, start, i - 1);
                start = i + 1;
            }
        }
        return s;
    }
};

55.卡码网【右旋字符串】

题目链接

解题过程

  • 三次分区间反转即可完成右旋字符串

知识点

  • 左旋的话,先旋转局部再旋转全局比较方便

右旋字符串

#include<iostream>
#include<string>
using namespace std;
void myReverse(string& s, int left, int right) {
    while (left < right) {
        swap(s[left++], s[right--]);
    }
}
int main() {
    int k;
    char c;
    string str;
    cin >> k;
    while (cin >> c) str += c;
    myReverse(str, 0, str.size() - 1);
    myReverse(str, 0, k - 1);
    myReverse(str, k, str.size() - 1);
    for (char c : str) cout << c;
    cout << endl;
    return 0;
}

28.找出字符串中第一个匹配项的下标

题目链接

解题过程

  • 知道本题可以用KMP做,但是还是选择了暴力法,KMP等有时间再细看

知识点

  • KMP时间复杂度: O(n + m),空间复杂度: O(m)
  • 暴力时间复杂度: O(n * m),空间复杂度: O(1)

暴力法

class Solution {
public:
    int strStr(string haystack, string needle) {
        for (int i = 0; i < haystack.size(); i++) {
            if (haystack[i] == needle[0]) {
                int j;
                for (j = 0; j < needle.size(); j++) {
                    if (haystack[i + j] != needle[j]) break;
                }
                if (j == needle.size()) return i;
            }
        }
        return -1;
    }
};

459.重复的子字符串

题目链接

解题过程

  • 本题可用KMP,但理论比较麻烦,就没做这个方法
  • 用暴力法也没做出来,看到有移动匹配的方法感觉不错,参考一下

知识点

  • 移动匹配的时间复杂度: O(1)空间复杂度: O(1)
  • string中find()返回值是字母在母串中的位置(下标记录),如果没有找到,那么会返回一个特别的标记npos。(返回值可以看成是一个int型的数)
  • 也可以查找某一给定位置后的子串的位置
  • 此代码由大力王提供,太厉害了,下面是Yves的解析:
  • 如果一个字符串可以由多个重复子串构成,即具有循环节 设最小循环节用a来表示,他代表通过子串a重复多次可以构成s 即s换成a来表示就是aa···aaa,由多少个最小循环节a构成s,那么就有几个a
  • 找循环节一个一个对比比较麻烦,最简单方法就是s+s就可以直接增加多一倍的循环节
  • 假设原来s=aaaa,那ss=s+s=aaaa aaaa 因为是不断重复的循环节,可以通过简单的屏蔽的第一个字符,然后再在ss中寻找s 因为屏蔽第一个字符,即第一个最小循环节被破坏,所以找到的s应该是从第二个循环节开始
  • 但倘若不是由一个子串重复构成 即s=abcd,那ss=abcd abcd=s+s 屏蔽掉第一个字符,又因不匹配,所以在ss中寻找s,一定是对应着新增s的位置,即s.size()处
class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size();
    }
};

字符串总结

字符串理论基础

  • 在C语言中,把一个字符串存入一个数组时,也把结束符 '\0’存入数组,并以此作为该字符串是否结束的标志。
  • 在C++中,提供一个string类,string类会提供 size接口,可以用来判断string类字符串是否结束,就不用’\0’来判断是否结束。
  • vector< char > 和 string 在基本操作上没有区别,但是 string提供更多的字符串处理的相关接口,例如string 重载了+,而vector却没有。所以想处理字符串,我们还是会定义一个string类型。

字符串经典题目


双指针总结

数组篇

  • 27. 移除元素
    • 通过两个指针在一个for循环下完成两个for循环的工作。

字符串篇

  • 344.反转字符串
    • 使用双指针法,定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。
  • 替换数字
    • 首先扩充数组到每个空格替换成char之后的大小。然后双指针从后向前替换空格。
    • 很多数组(字符串)填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
  • 151.翻转字符串里的单词
    • 删除冗余空格的过程中,如果不注意代码效率,很容易写成了O(n^2)的时间复杂度。其实使用双指针法O(n)就可以搞定。
    • 删除空格后就可以分区间反转

链表篇

  • 206.反转链表
    • 使用双指针法来翻转链表,只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。
  • 142.环形链表II
    • 使用快慢指针(双指针法),分别定义 fast 和 slow指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
    • 找到环的入口,需要数学推理,链接里有推理过程

N数之和

  • 15. 三数之和
    • 这道题目使用双指针法才是最为合适的,用双指针做这道题目才能就能真正体会到,通过前后两个指针不断向中间逼近,在一个for循环下完成两个for循环的工作。
    • 使用哈希法的过程中要把符合条件的三元组放进vector中,然后在去去重,这样是非常费时的
  • 18. 四数之和
    • 三数之和的基础上再套一层for循环,依然是使用双指针法。
    • 对于三数之和使用双指针法就是将原本暴力O(n^ 3)的解法,降为O(n ^2)的解法,四数之和的双指针解法就是将原本暴力O(n ^4)的解法,降为O(n ^3)的解法。
  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值