代码随想录算法训练营Day9 | Leetcode 151 翻转字符串里的单词 Leetcode 28 实现strStr() Leetcode 459 重复的字字符串 卡码网 右旋字符串

前言

万恶的KMP算法,折磨人的KMP算法。但这次对KMP算法有了新的理解,逐渐理解不用重复匹配匹配过的子串这个概念了。

Leetcode 151 翻转字符串里的单词

题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/

代码随想录题解:代码随想录 (programmercarl.com)

思路:分成三步,去除多余空格,翻转整个字符串,翻转单词。去除多余空格:空格在三个部分出现,头,中,尾。头的需要全删掉,所以我们最简单的判断逻辑就能实现,遍历到第一个字母开始存。中的空格需要多加一步,如果当前字符不为空格且slow!=0(证明已经存过单词了),此时先加一个空格然后再存单词即可,尾部的也很简单,不是字母不存就行。翻转字符串不多讲,昨天已经实现过一次。翻转单词则是先记录初始位置,如果遍历到空格就翻转初始位置到当前位置的字符串,然后更新起始位置到空格下一个字符也就是新单词的开头。

代码:

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 delspace(string &s)
    {
        int slow=0;
        for(int fast=0;fast<s.size();fast++)//类似移除字符中的快慢指针
        {
         if(s[fast]!=' ')//自动过滤头和尾
         {
            if(slow!=0)//如果已经存了单词 此时遍历到第二个单词的开头 先存一个空格
            {
                s[slow]=' ';
                slow++;
            }
            while(fast<s.size()&&s[fast]!=' ')//存入这个单词
            {
                s[slow]=s[fast];
                slow++;
                fast++;
            }
         }
        }
        s.resize(slow);//记得写
    
    }
    string reverseWords(string s) {
    delspace(s);
    reverse(s,0,s.size()-1);
    int start=0;//记录起始位置
    for(int i=0;i<=s.size();i++)
    {
        if(s[i]==' '||i==s.size())//后半句是保证翻转最后一个单词
        {
        reverse(s,start,i-1);
        start=i+1;更新起始位置
        }
    }
    return s;
    }
};

Leetcode 28 实现strStr()

题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

代码随想录题解:代码随想录 (programmercarl.com)

思路:先说KMP,感觉需要记住计算NEXT数组的动图,匹配最长公共前后缀。放弃了,我无法用语言形容这个过程,只能意会,各位看图吧。

class Solution {
public:
    void getnext(int *next,string s)
    {
    int j=0;
    next[0]=0;
    for(int i=1;i<s.size();i++)
    {
        if(s[i]==s[j])
        {
            j++;
            next[i]=j;
        }
        while(j>0&&s[i]!=s[j])
        {
         j=next[j-1];
        }
    } 
    }
    
    int strStr(string haystack, string needle) {
if (needle.size() == 0) {
            return 0;
        }
        int next[needle.size()];
        getnext(next, needle);
        int j = 0;
        for (int i = 0; i < haystack.size(); i++) {
            while(j > 0 && haystack[i] != needle[j]) {
                j = next[j - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == needle.size() ) {
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};

Leetcode 459 重复的字字符串 

题目链接:https://leetcode.cn/problems/repeated-substring-pattern/

代码随想录题解:代码随想录 (programmercarl.com)

思路:例如s=abcabc由abc组成,那么如果我们将s+s然后将头尾去掉得到bcabcabcab,可以看出其中必然包括一个s。

代码:

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
     string ss=s+s;
     ss.erase(ss.begin());
     ss.erase(ss.end()-1);
     if(ss.find(s)!=string::npos)
     {
        return true;
     }
     return false;
    }
};

卡码网 右旋字符串

题目链接:55. 右旋字符串(第八期模拟笔试) (kamacoder.com)

代码随想录题解:代码随想录 (programmercarl.com)

思路:和翻转字符串里的单词思路差不多,只不过需要限定翻转范围。第一步翻转整个字符串,第二步按范围翻转字符串的各个部分。

代码:

#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;

} 

C++ 深拷贝与浅拷贝

1.什么是深拷贝,浅拷贝? 

每个对象都占有一块内存,在复制对象的过程中,浅拷贝复制出来的对象与原对象共享一块内存。而深拷贝复制出来的对象另开辟了一片内存并占有,不共享原对象的内存空间。

2.如何实现深拷贝,浅拷贝?

浅拷贝一般依靠编译器给出的默认拷贝构造函数和拷贝赋值函数,他们的实现一般就是简单的赋值。而深拷贝则需要我们自己给出拷贝构造函数和拷贝赋值函数,里面必须有动态分配的内存。

3.区别与问题

一般出现在这个对象里面有指针变量时,浅拷贝可以理解为将对象里面的指针变量赋值给一个新的指针变量,两个指针指向同一块内存地址;而深拷贝则将数据复制一份并开辟一块新内存,由一个新的指针指向。如果我们采用浅拷贝,对拷贝过来的对象或者原对象进行增删改等操作,会同时影响两个对象,而且在调用析构函数的时候会对一片内存释放两次内存空间,可能会引发一些意外的问题。

4.拷贝构造函数和拷贝赋值函数

拷贝构造函数一定要用引用传递参数,如果是值传递参数的话会导致递归调用。原理是当我们用值传递给一个函数参数时,会自动调用拷贝构造函数形成一个副本给函数使用,此时这个拷贝构造函数的参数也需要一个值传递,那么又会调用一个拷贝构造函数,就会递归调用,所以必须是引用传参。拷贝赋值函数其实就是对赋值运算符重载,他的参数列表隐含了一个this指针,我们在自己实现拷贝赋值函数的时候必须用这个this指针判断当前对象是否为空,如果不为空需要析构当前对象释放空间,否则也会出现内存泄漏的风险。

总结

KMP算法你罪大恶极,我完全无法用语言描述你运作的过程。操作系统比计网有意思,计网感觉没什么道理,死记硬背。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值