LeetCode 刷题 -- Day 4

今日题目

题目难度备注
344. 反转字符串 简单
541. 反转字符串 II简单考察模拟过程能力
151. 反转字符串中的单词中等
28. 找出字符串中第一个匹配项的下标简单KMP
459. 重复的子字符串 简单

题目:344. 反转字符串

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

一、源代码

//头尾交换即是反转
void reverseString(vector<char>& s) {
        for (int i = 0; i < s.size()/2; i++){
            int temp = s[i];
            s[i] = s[s.size()-i-1];
            s[s.size()-i-1] = temp;
        }
    }

二、代码思路

经典数组 / 字符串反转代码,首尾元素交换即为反转


题目:[541. 反转字符串 II

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

一、源代码

class Solution {
private:
    string reverseBtw(string s, int l, int r) {
        for (int i = l; i <= (l + r) / 2; i++) {
            int temp = s[i];
            s[i] = s[r + l - i];
            s[r + l - i] = temp;
        }
        return s;
    }

public:
    string reverseStr(string s, int k) {
        int len = s.size();
        for (int i = 0; i <= len; i += 2 * k) {
            if (i != 0) {
                s = reverseBtw(s, i - 2 * k, i - k - 1);
            }
            if (len - i < k) { // 如果剩余字符少于k个
                s = reverseBtw(s, i, len - 1);
                break;
            } else if (len - i < 2 * k) { // 如果剩余字符少于2k个
                s = reverseBtw(s, i, i + k - 1);
                break;
            }
        }
        return s;
    }
};

二、代码思路

从1开始计数,在计数开始前或每数到 2k 时都进行判断处理一次 ①数到2k的倍数则反转前k个,②剩余字符少于k个则全部反转并结束,③ 如果剩余字符少于2k个 但大于等于 k 个则反转前k个并结束。

要实现:从1开始计数,在计数开始前或每数到 k 时都进行某种操作,可定义 for ( i = 0; i <= len; i+=k) 以及用 i % k == 0 来判断

三、优化思路

模拟过程,显然观察区长度为 2k,遍历每个观察区进行处理。对每个观察区,有两种处理情况:

① 反转前 k 个,条件为剩余字符数大于等于 k个

② 剩余字符全部反转,条件为剩余字符数小于 k个

显然观察区长度为 2k,可用 for 循环遍历观察区 for (int i = 0; i < n; i += 2 * k) ,i 为观察区第一个元素下标,则 ① 为 reverse(s.begin() + i, s.begin() + i + k); ② 为 reverse(s.begin() + i, s.begin() + n); 若 i + k > n,说明此观察区剩余字符数量小于 k 个,应全部反转

四、优化代码

class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.length();
        for (int i = 0; i < n; i += 2 * k) {
            reverse(s.begin() + i, s.begin() + min(i + k, n));
        }
        return s;
    }
};

题目:151. 反转字符串中的单词

151. 反转字符串中的单词 - 力扣(LeetCode)

一、源代码

string reverseWords(string s) {
        vector<string> wd;
        int i = 0;
        string ans = "";
        while (i < s.size()) {
            string temp = "";
            while (s[i] != ' ' && i < s.size()) { // 获取单词
                temp += s[i++];
            }
            if (temp != "") {  //单词不为空则存起来
                wd.push_back(temp);
            }
            if (i < s.size()) {
                i++;
            }
        }
        for (int j = wd.size() - 1; j >= 0; j--) {
            ans += wd[j];
            if (j > 0) {
                ans += ' ';
            }
        }
        return ans;
    }

二、代码思路

把字符串拆分成一个个的单词,压入数组,最后逆序遍历数组,即为结果。


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

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

一、源代码

    int strStr(string haystack, string needle) {
        int lenH = haystack.size(), lenD = needle.size();
        if (lenH < lenD) {  
            return -1;
        }
        for (int i = 0; i <= lenH - lenD; i++) {  //遍历haystack
            int cnt = 0,p = i, j = 0;
            while (haystack[p] == needle[j] && p < lenH && j < lenD){ //若元素相同则进行匹配cnt++;
                ++cnt; ++p; ++j;
            }
            if (cnt == lenD){  //若匹配成功
                return i;
            }
        }
        return -1;
    }

二、优化思路

源代码为简单暴力匹配,字符串模式匹配要时间复杂度低当然得用KMP算法

三、优化代码

     int strStr(string s, string p) {
        int n = s.size(), m = p.size();
        if(m == 0) return 0;
        //设置哨兵
        s.insert(s.begin(),' ');
        p.insert(p.begin(),' ');
        vector<int> next(m + 1);
        //预处理next数组
        for(int i = 2, j = 0; i <= m; i++){
            while(j and p[i] != p[j + 1]) j = next[j];
            if(p[i] == p[j + 1]) j++;
            next[i] = j;
        }
        //匹配过程
        for(int i = 1, j = 0; i <= n; i++){
            while(j and s[i] != p[j + 1]) j = next[j];
            if(s[i] == p[j + 1]) j++;
            if(j == m) return i - m;
        }
        return -1;
    }

题目:459. 重复的子字符串

459. 重复的子字符串 - 力扣(LeetCode)

一、源代码

class Solution {
private:
    bool canCompa(string s, string sb) {   //判断s是不是由sb组成的
        while (s.find(sb) != s.npos) {
            s.erase(s.find(sb), sb.size());
        }
        return s.size() == 0 ? true : false;
    }

public:
    bool repeatedSubstringPattern(string s) {
        if (s.size() == 1)
            return false;
        int p = 2; // 划分字符串
        string sb = s;
        while (sb.size() != 1) {
            if (s.size() % p == 0 || s.size() / p == 1) {   //可将s均分,或拆成长度为1的子串
                sb = s.substr(0, s.size() / p); //将s拆分成长度不同的子串
                if(canCompa(s, sb)){
                    return true;
                }
            }
            ++p;
        }
        return false;
    }
};

二、优化思路

若 s 可由若干相同字串 s‘ 组成,即 s = s’ s’ … s’ 。有性质:将 s 中第一个(或前k个) s‘ 移去,再 s 末尾加入一个 (或k个)s’ ,则 s 不变。所以若 s = s’ s’ … s’ ,将 s 的首尾拼接(ss)后,中间会出现 s。ss = s’ s’ … s’ s’ s’ … s’ ,中间一定有s的出现。所以若将两个s 连在一起,并移除第一个和最后一个字符,那么得到的字符一定包含 s。

可用这个性质进行判断,不用枚举子串判断。

三、优化代码

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size(); // ss拼接,从下标为1的位置开始找s
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值