2024/4/25 代码随想录Day 9:28. 实现 strStr() 459.重复的子字符串 字符串总结 双指针回顾

2024/4/25 代码随想录Day 9:28. 实现 strStr() 459.重复的子字符串 字符串总结 双指针回顾

28. 实现 strStr()

题目链接 28 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。

第一次提交

常看常新
随想录

SolutionDemo

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size();
        int n = needle.size();
        if (n == 0) return 0;
        vector<int> next(n);
        for (int front = 0, back = 1; back < n; back++) {
            while(front > 0 && needle[front] != needle[back]) front = next[front-1];
            if (needle[front] == needle[back]) front++;
            next[back] = front;
        }
        for (int pat = 0,str = 0; str < m; str++) {
            while(pat > 0 && haystack[str] != needle[pat]) pat = next[pat-1];
            if (haystack[str] == needle[pat]) pat++;
            if (pat == n) return str - n + 1;
        }
        return -1;
    }
};

整理一下

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

本质上findNext是在match的时候记录了一些中间结果

class Solution {
public:
    int matchMessagePattern(string message, string pattern, vector<int> &next, bool getNext) {
        int m = message.size();
        int n = pattern.size();
        if (getNext) next = vector<int>(m);
        for (int i = 0, j = 0; i < m; i++) {
            if (getNext && i == 0) continue;
            while(j > 0 && message[i] != pattern[j]) j = next[j - 1];
            if (message[i] == pattern[j]) j++;
            if (getNext) next[i] = j;
            if (j == n) return i - n + 1;
        }
        return -1;
    }
    int strStr(string haystack, string needle) {
        int m = haystack.size();
        int n = needle.size();
        vector<int> next(n);
        int _ = matchMessagePattern(needle, needle,next, true);        
        return matchMessagePattern(haystack, needle, next, false);
    }
};

学习一下python 函数

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        try:
            return haystack.index(needle)
        except ValueError:
            return -1

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        return haystack.find(needle)

459.重复的子字符串

题目链接 459

第一次提交

太暴力了

class Solution {
public:
    bool check(string s, int i) {//abac
        int n = s.size();
        int times = n/i;
        cout <<times<<endl;
        for (int r = 0 ; r < i; r++) {
            for (int t = 0; t < times - 1 ; t++) {
                //cout <<t* i + r<< " "<< t*i + t + r<<endl;
                if(s[t* i + r] != s[t*i + i + r]) return false;
            }
        }
        return true;
    }
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        int rep = n/2;
        for ( int i = 1; i <= rep; i++) {
            if (n % i == 0){
                cout<< s << i<< endl;
                if (check(s, i)) return true;
            }
        }
        return false;
    }
};

学习优秀题解

随想录

视频

优雅的数学方法

移动匹配方法

class Solution {
public:
    bool kmp(string quary, string pattern) {
        int m = quary.size();
        int n = pattern.size();
        vector<int>next(n);
        for (int i = 1 , j = 0; i < n; i++) {
            while(j > 0 && pattern[i] != pattern[j]) j = next[j-1];
            if (pattern[i] == pattern[j]) j++;
            next[i] = j;
        }
        for (int i = 0 , j = 0; i < m; i++) {
            while(j > 0 && quary[i] != pattern[j]) j = next[j-1];
            if (quary[i] == pattern[j]) j++;
            if (j == n) return true;
        }
        return false;
    }
    bool repeatedSubstringPattern(string s) {
        string doubles = s+s;
        doubles.pop_back();
        doubles.erase(0, 1);//这里注意erase的用法,起始位置+个数
        cout<< doubles<< endl;
        return kmp(doubles, s);
    }
};

学习一下库函数

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size();
    }
};

find 函数

string (1)
size_t find (const string& str, size_t pos = 0) const;

c-string (2)
size_t find (const char* s, size_t pos = 0) const;

buffer (3)
size_t find (const char* s, size_t pos, size_t n) const;

character (4)
size_t find (char c, size_t pos = 0) const;

更优雅的前后字串方法

类KMP方法,构造next数组

比较惊艳的是两个点,一个是前后缀的解决思路,还有一个是判断条件是整除为0

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        //find next(n-1)
        int n = s.size();
        vector<int> next(n);
        for (int i = 1, j = 0; i < n; i++) {
            while(j > 0 && s[i] != s[j]) j = next[j -1];
            if (s[i] == s[j]) j++;
            next[i] = j;
        }
        return next[n - 1] != 0 && n % (n - next[n - 1]) == 0;
    }
};

字符串&双指针总结

几道经典题重新写一下

双指针法

151.反转字符串中的单词

分解成去除和反转两个功能,注意最后判断边界

  1. 去除多余0
  2. 反转
  3. 反转单个单词
class Solution {
public:
    void removeExtraBlank(string& s) {//slow fast index
        int slow = 0, fast = 0;
        int n = s.size();
        while(s[fast] ==' ') fast++;
        for (; fast < n; fast++) {
            if (s[fast] != ' ') {
                s[slow] = s[fast];
                slow++;
            } else if (s[fast] == ' ' && fast+1 < s.size()&& s[fast+1] != ' ') {
                s[slow] = s[fast];
                slow++;
            }
        }
        s.resize(slow);
    }
    void reverse(string& s, int start, int end) {
        int half = (end - start) / 2;
        for (int i = 0; i < half; i++) {
            swap(s[start + i], s[end - 1 - i]);
        }

    }
    string reverseWords(string s) {
        removeExtraBlank(s);
        cout<< s << endl;
        reverse(s, 0, s.size());
        int start = 0;
        for (int i = 0; i <= s.size(); i++) {
            if (i == s.size()) {
                reverse(s, start, i);
                break;
            }
            if (s[i] == ' ') {
                reverse(s, start, i);
                start = i + 1;
            }            
        }
        return s;
    }
};

142.环形列表2

快慢指针,暴力用哈希表,优雅的数学方法

这次写需要注意while大循环终止条件的判定,如果只判定fast不为空, fast->next->next 有可能会访问到空指针

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head == nullptr) return nullptr;
        if (head->next == nullptr) return nullptr;
        ListNode * slow = head->next, * fast = head->next->next;
        while(fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) {
                fast = head;
                while(slow != fast) {
                    slow = slow->next;
                    fast = fast->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};

15.三数之和

细节重点在去重,这一遍第一次尝试出现的问题是去重之前应该先left,right各内缩。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) { 
        vector<vector<int>> res; 
        int n = nums.size();
        sort(nums.begin(), nums.end());
        for(int i = 0; i < n; i++) {
            if (i > 0 && nums[i] == nums[i-1]) continue;
            if (nums[i] > 0) return res;
            int right = nums.size() - 1;
            int left = i+1;
            while(left < right) {
                if (nums[i] + nums[left] + nums[right] == 0) {
                    res.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    left ++;//这里要注意
                    right --;
                    while(left > i+1 && nums[left] == nums[left-1] && left < right) left++;
                    while(right < nums.size()-1  && nums[right] == nums[right + 1] && left < right) right--;
                } else if (nums[i] + nums[left] + nums[right] > 0) {
                    right --;
                } else {
                    left ++;
                }
            }
        }
        return res;
    }
};

18.四数之和

同上,多的只是工程量,还有剪枝的思考,今天不重新写了

KMP

今天的内容,再优雅ac一次

KMP 28

一把过

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

重复子字符串 459

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        vector<int> next(n);
        for(int i = 1, j = 0; i < n; i++) {
            while (j > 0 && s[i] != s[j]) j = next[j-1];
            if (s[i] == s[j]) j++;
            next[i] = j;
        }
        if (next[n-1] == 0) return false;
        return n % (n - next[n-1]) == 0 ? true : false;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值