代碼隨想錄算法訓練營|第九天|28. 实现 strStr()、459.重复的子字符串、字符串总结、双指针回顾。刷题心得(c++)

目录

讀題

28. 实现 strStr()

自己看到题目的第一想法

看完代码随想录之后的想法

459.重复的子字符串

自己看到题目的第一想法

看完代码随想录之后的想法

28. 实现 strStr() - 實作

思路

m * n 思路

m + n 思路

Code

m * n

m+n

459.重复的子字符串 - 實作

思路

Code

字符串總結筆記

庫函數的使用

雙指針法

花式反轉

KMP

總結

雙指針回顧筆記

數組

字符串

鏈表

N數之和

總結

總結

自己实现过程中遇到哪些困难

今日收获,记录一下自己的学习时长

相關資料


讀題

28. 实现 strStr()

自己看到题目的第一想法

看到的第一個想法是使用滑動窗口的方法,從零開始,假設第一個字符與needle字符相等,則進入迴圈,假設迴圈當中有不符合的狀況,跳出迴圈,如果一致return i ,都不一致則return -1;

看完代码随想录之后的想法

初見KMP算法,還有很多細節要著墨的,但今天在思考的過程中,原本m * n 的解法改為,主字串只要走一遍,至於比較的部分我利用子字符串他的規律來進行跳動

比如說今天要找aafaae這個子字串,我們可以觀察到,aa是相同的部分

那在aafaafaae我要在裡面找到這個子字串

如果用原本的方法,我走到aafaa”f” 這個f因為跟我的子字串的”e”不相符,所以我的i會跳回去主字串的第二個a,再依序往後比對

但假設使用KMP 我知道aafaae他所組成的next數組是 [ -1, 0, -1, 0, 1, -1],假設我比對到aafaa”f”時我可以利用這個數組跳到上一個aa在的地方,也就是a”a”faae的ˋ第二個a的地方之後在+1比對兩個字串目前的字元是否一致。

目前講得還是會比較攏統,但是以這個想法來寫,效率真的提高蠻多的,需要再花點時間琢磨琢磨

459.重复的子字符串

自己看到题目的第一想法

看到這個題目的提示是使用KMP法,我聯想到建立NEXT數組的時候,我們會對於整體去做J要如何移動的依據,嘗試進行畫圖會發現,如果是重複的,並且有發現到一個可能的規律是在於,是由重複的子字符串進行比對,如果以兩個字幅串比對,並且每組都是九個為一組,納第二組的j最後就會++到八,感覺有點聯繫,但實在想不出來要怎麼解

看完代码随想录之后的想法

看完之後,比較快可以理解,透過減去最長相等的後輟的特性,我們可以知道除了第一組之外的長度,也就是後續不斷++的長度,假設next最後一個數是八 整個字串長度是18 那我們可以知道 最長後輟長度是九 整個字串長度減去最長後輟的長度,就會等於第一組的長度,假設這個長度能夠整除18%9 餘零,代表這是一個長度為九,重複兩次的字串

28. 实现 strStr() - 實作

思路

m * n 思路

  1. 設定一個need = 0 → 用來存放起始位置
  2. 進入迴圈,逐步往前 → 因為起始點有可能在第二個,
    1. 假設i 跟子字符串的起始點相同,則進入判斷式
      1. need = i; → 存放起始位置
      2. 進入迴圈,假設i < haystack.size && j < needle.size → 避免操作到空數組
        1. 如果haystack[i] == needle[j] 則i, j++
        2. 如果不同 i回到起始位置,j返回0 ,跳出迴圈
        3. 假設j == needle.size() 代表包含子字符串,回傳need
  3. 迴圈結束,都沒有子字符串相等,回傳 -1;

m + n 思路

  1. 為needle字串建立一個next的數組,用來標記j 要怎麼跳
  2. 設定j = -1;
  3. for迴圈,遍歷haystack字串
    1. 假設haystack[i] ≠ needle[j + 1] 並且j >= 0 → j + 1 的原因是因為j 等於-1 j ≥ 0 才需要回跳,不然j+1 = 0 needle會保持在0的位置
      1. j = needle[j] → 跳到與之前相符的位置 也就是aafaa 從第二組aa的第一個a 跳到第一組aa的第二個a
    2. 假設相等 j++;
    3. if ( j == (t.size - 1) { return i - j; }
    4. else return -1

Code

m * n

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

m+n

class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.size() == 0){
            return 0;
        }
        int next[needle.size()];
        int j = -1, i = 0;
        next[0] = j;
        for(i = 1; i < needle.size(); i++){
            while(j >= 0 && needle[i] != needle[j + 1]) {
                j = next[j];
            }
            if(needle[i] == needle[j + 1]) { // 因為也有可能不等於
                j++;
            }
            next[i] = j;
        }
        j = -1;
        for(i = 0; i < haystack.size(); i++) {
            while(j >= 0 && haystack[i] != needle[j + 1]) {
                j = next[j];
            }
            if(haystack[i] == needle[j + 1]) {
                j++;
            }
            if(j == needle.size() - 1) {
                return i - j;
            }
        }
        return -1;
    }
};

459.重复的子字符串 - 實作

思路

  1. 將字串轉換成next數組,並且取最後一個數
  2. 最後一個數+1 → 取得最長後輟長度
  3. 整個字符串長度 - 最長後輟長度 = 最小前輟長度
  4. 整個字符串長度 % 最小前輟長度 == 0 代表重複,不等於代表不重複

Code

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

字符串總結筆記

庫函數的使用

在字符串的學習當中,因為之前都是碰C,所以對於C++的庫函數都很不熟悉,比如最基礎的swap以及reverse都不太熟悉,但是正因為這個事情,所以我比較少去依賴庫函數,常常會想自己做,不過這個過程中,也是真的很有趣,比如說反轉字串,我學到了還可以用位運算進行字串反轉,真的是驚到我了

雙指針法

在學習反轉字串的時候,雙指針法真的很好用,其實廣義來說KMP也是用到兩個指針,來進行變換,讓我了解到,不是有越多工具越好,有時可以把一項精典工具用精,就可以很容易的去處理

花式反轉

在反轉字符串ll 以及翻轉字符串的單詞,以及左旋轉字符串,都讓我感到很好玩,原來程式可以這麼花式,並且我在跟其他群組的小夥伴討論左旋轉字符串時,我還了解到這個如果要深究還可以牽涉到某個數論,真的非常有趣

KMP

我不敢說我自己已經了解了,在學習KMP的過程當中,其實碰到很多困難,但就是靜下心來去畫圖,重複看好幾片影片以及小夥伴提供的資料去輔助,我感覺到後面寫起來是知道為甚麼這一段CODE要這麼寫,而不是照著模板,這樣的學習真的很讓人滿足

總結

字符串就像卡哥說的,想法很簡單,但實現起來其實有很多眉眉角角要進行處理,雙指針法好好用,KMP法要想辦法更加了解其精隨,學習字符串的過程中,感覺到最多的不是困難,而是有趣,尤其是自己想盡辦法思考出來的思路,假設有一點點跟提解接近,那就會很開心了。

雙指針回顧筆記

數組

不論是二分法、滑動窗口、快慢指針,就是根據不同題目的調性,去靈活運用兩個指針彼此的關係,回到第一點,只要定義清楚了,其實雙指針的做法很快就可以根據自己的思路進行設計。

字符串

字符串在反轉字串、以及KMP都有用兩個指針在那進行交換

並且在反轉字串時,雙指針可以針對不同的需求去做應用,比如說只反轉前K個就可以讓指針去自己想定位的位置

鏈表

雙指針非常重要,不論是206.反转链表還是142.环形链表II,都是解題的關鍵

尤其是環形鏈表ll,使用快慢指針,並且這道題目還可以用數學的方式去理解,真的很好玩

N數之和

最後就是15.三數之和以及18.四數之和,這兩道題目我看著我當初的思路,真的沒有想到就是利用雙指標來解決這道題目,

就算卡哥有提示可以我也沒有想得很明白,直到看完卡哥兩題的解題思路,我突然豁然開朗

15.三數之和重點就是四個

  • 排序 → 為了雙指針的變動以及去重的方便
  • 第一個數位置要放哪
  • 雙指針的範圍要怎麼設定
  • 以及如何去重

18.四數之和重點多一個

  • 排序 → 為了雙指針的變動以及去重的方便
  • target有可能是負數,要記得在剪枝時要進行判斷
  • 第一個數以及第二個數位置要放哪
  • 雙指針的範圍要怎麼設定
  • 以及如何去重

在雙指針的寫法當中,我在這種左右邊界的雙指針,我學到了要記得排序,不然這個雙指針會沒辦法使用,而我一開始沒有想到的就是這點,想到這點之後就比較通透了。

總結

對於雙指針法我不能說熟練,只能說目前就是了解,以及稍微會使用了,感覺這個方法後續還會一直碰到,找個時間再來複習。

總結

自己实现过程中遇到哪些困难

KMP算法真的理解很久,但目前掌握到一點皮毛了,後續會對於這個部分在進行更深入的了解

今日收获,记录一下自己的学习时长

今日大概學了3、4HR 左右,工作比較忙,但了解了一點KMP的概念後,真的很開心。

相關資料

  1. 实现 strStr()

题目链接/文章讲解/视频讲解:https://programmercarl.com/0028.实现strStr.html

459.重复的子字符串 (本题可以跳过)

题目链接/文章讲解/视频讲解:https://programmercarl.com/0459.重复的子字符串.html

字符串总结

题目链接/文章讲解:https://programmercarl.com/字符串总结.html

双指针回顾

文章讲解:https://programmercarl.com/双指针总结.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值