<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ?LeetCode刷題實(shí)戰(zhàn)159:至多包含兩個(gè)不同字符的最長(zhǎng)子串

          共 4887字,需瀏覽 10分鐘

           ·

          2021-01-19 13:55

          算法的重要性,我就不多說了吧,想去大廠,就必須要經(jīng)過基礎(chǔ)知識(shí)和業(yè)務(wù)邏輯面試+算法面試。所以,為了提高大家的算法能力,這個(gè)公眾號(hào)后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !

          今天和大家聊的問題叫做?至多包含兩個(gè)不同字符的最長(zhǎng)子串(這題Leetcode需要會(huì)員才能看),我們先來看題面:
          https://leetcode-cn.com/problems/longest-substring-with-at-most-two-distinct-characters/

          Given a string, find the length of the longest substring T that contains at most 2 distinct characters.

          題意

          給定一個(gè)字符串 s ,找出 至多 包含兩個(gè)不同字符的最長(zhǎng)子串 t 。

          樣例

          1:

          輸入: “eceba”
          輸出: 3
          解釋: t 是 “ece”,長(zhǎng)度為3

          2:

          輸入: “ccaabbb”
          輸出: 5
          解釋: t 是 “aabbb”,長(zhǎng)度為5。



          解題

          https://www.jianshu.com/p/3494e4dcea00

          解題思路



          一. 理解題意
          • 要求是子串,不是子序列

          • 子串最多由兩個(gè)不同字符 按任意數(shù)量 排列組合而成

          • 不要求記錄子串,只需要記錄長(zhǎng)度

          二. 選擇數(shù)據(jù)結(jié)構(gòu)與算法
          雙指針 + 哈希表 解法
          • 數(shù)據(jù)結(jié)構(gòu):指針、哈希表

          • 算法思維:遍歷、雙指針、哈希(散列)


          解題思路

          1. 聲明一個(gè)哈希表和一個(gè)哈希函數(shù)
            ? 哈希函數(shù)用于生成字符索引
            ? 哈希表存放該字符在子串中出現(xiàn)的個(gè)數(shù)

          2. 聲明一個(gè)整形變量存放“不同字符”的個(gè)數(shù),按照題目要求,此個(gè)數(shù)應(yīng)當(dāng) <= 2

          3. 用左右兩個(gè)指針遍歷整個(gè)字符串
            ? 判斷右指針字符是否是“新字符”
            ? ? 如果是新字符,不同字符數(shù) +1
            ? ? 無論是否為新字符,右指針在哈希表中相應(yīng)位置的數(shù)據(jù)都要 +1,表示右指針字符在子串中出現(xiàn)的次數(shù) +1
            ? ? 不斷判斷不同字符數(shù)是否 > 2
            ? ? ? 如果大于2,左指針在哈希表中相應(yīng)位置的數(shù)據(jù) -1,表示左指針字符在子串中出現(xiàn)的次數(shù) -1
            ? ? ? 判斷左指針在哈希表中相應(yīng)位置的數(shù)據(jù)是否 == 0
            ? ? ? ? 如果不為 0,說明當(dāng)前刪除的左指針字符不是子串中的“最后一個(gè)”,右移左指針
            ? ? ? ? 如果為 0,說明當(dāng)前刪除的左指針字符是子串中的“最后一個(gè)”,不同字符數(shù) -1

          4. 不管任何情況,右指針都照常右移

          5. 每次右指針右移時(shí),計(jì)算最長(zhǎng)子串的長(zhǎng)度

          邊界問題
          • 右指針(b)領(lǐng)先左指針(a),因此邊界條件為:b < s.length()

          細(xì)節(jié)問題
          • 子串長(zhǎng)度的計(jì)算公式:
            如果先計(jì)算長(zhǎng)度,右指針再右移,則
            subLen = b - a +1
            如果右指針先右移,再計(jì)算長(zhǎng)度,則 subLen = b - a


          class?Solution?{
          ????public?int?lengthOfLongestSubstringTwoDistinct(String s)?{

          ????????int?len = s.length();

          ????????//定義哈希表
          ????????int[] hashtable = new?int[128];
          ????????for?(int?i = 0; i < 128; i++){
          ????????????hashtable[i] = 0;
          ????????}

          ????????int?a = 0; //左指針
          ????????int?b = 0; //右指針
          ????????int?count = 0; //不同字符的個(gè)數(shù)
          ????????int?subLen = 0; //最長(zhǎng)子串的長(zhǎng)度
          ????????
          ????????//遍歷字符串
          ????????while?(b < len) {
          ????????????char?cb = s.charAt(b);
          ????????????//如果 b 處字符不存在于哈希表中
          ????????????if?(hashtable[hash(cb)] == 0){
          ????????????????count++; //不同字符個(gè)數(shù) +1
          ????????????}
          ????????????//哈希表對(duì)應(yīng)位置 +1
          ????????????hashtable[hash(cb)]++;
          ????????????
          ????????????//直到不同字符個(gè)數(shù) <= 2
          ????????????while?(count > 2){
          ????????????????char?ca = s.charAt(a);
          ????????????????hashtable[hash(ca)]--; //哈希表中 a 處字符對(duì)應(yīng)位置 -1
          ????????????????//如果哈希表中 a 處字符對(duì)應(yīng)位置不為 0
          ????????????????if?(hashtable[hash(ca)] == 0){
          ????????????????????count--; //不同字符個(gè)數(shù) -1
          ????????????????}
          ????????????????a++; //a指針右移
          ????????????}
          ????????????
          ????????????//計(jì)算子字符串長(zhǎng)度
          ????????????subLen = Math.max(subLen,b-a+1);
          ????????????b++;
          ????????}
          ????????return?subLen;
          ????}

          ????//定義哈希函數(shù)
          ????private?int?hash(char?c){
          ????????return?c;
          ????}
          }

          執(zhí)行耗時(shí):1 ms,擊敗了 100.00% 的Java用戶
          內(nèi)存消耗:36.6 MB,擊敗了 99.63% 的Java用戶
          時(shí)間復(fù)雜度:O(n) -- 兩次鏈表的遍歷 O(n),查詢哈希表 O(1)
          空間復(fù)雜度:O(1) -- 一個(gè)哈希表 O(1),兩個(gè)指針 O(1),兩個(gè)整數(shù)變量 O(1)

          使用“滑動(dòng)窗口”的算法思維解決問題

          優(yōu)化解法

          /**
          ?????* 解法一:采用滑動(dòng)窗口的算法思想,選取 left-right 子串進(jìn)行驗(yàn)證
          ?????* 如果字符數(shù)量沒有超過2,則記錄此時(shí)的最大長(zhǎng)度,并且 right++
          ?????* 如果字符數(shù)量超過2,則 left++
          ?????* 使用 map 存放出現(xiàn)過的字符及次數(shù)
          ?????*
          ?????* (優(yōu)化算法,使用數(shù)組替代 map)
          ?????*/

          ????public?int?lengthOfLongestSubstringTwoDistinct1(String s)?{
          ????????char[] chars = s.toCharArray();
          ????????int?len = chars.length;
          ????????Map map?= new?HashMap<>();
          ????????int?left = 0, right = 0;
          ????????int?count = 0;//不同的字符數(shù)量
          ????????int?maxLength = 0;
          ????????while?(right < len) {
          ????????????//在map中獲取該字符出現(xiàn)的次數(shù)(不存在則為0),次數(shù)+1
          ????????????int?rightNumber = map.getOrDefault(chars[right], 0) + 1;
          ????????????map.put(chars[right], rightNumber);//更新map
          ????????????if?(rightNumber == 1) {//第一次出現(xiàn)
          ????????????????count++;
          ????????????}
          ????????????right++;
          ????????????if?(count <= 2) {
          ????????????????maxLength = Math.max(maxLength, right - left);
          ????????????}
          ????????????while?(count > 2) {
          ????????????????//左側(cè)移除一個(gè)字符,在map中獲取該字符出現(xiàn)的次數(shù)-1
          ????????????????int?leftNumber = map.get(chars[left]) - 1;
          ????????????????map.put(chars[left], leftNumber);//更新map
          ????????????????if?(leftNumber == 0) {
          ????????????????????count--;
          ????????????????}
          ????????????????left++;
          ????????????}
          ????????}
          ????????return?maxLength;
          ????}

          最優(yōu)解

          /**
          ?????* 最優(yōu)解
          ?????* 改進(jìn)1:考慮 ASCII 碼表中的128個(gè)字符,可以使用數(shù)組代替 map,存放每個(gè)字符出現(xiàn)的次數(shù)
          ?????* 改進(jìn)2:滑動(dòng)窗口 只會(huì)擴(kuò)大或者平移(我們要取的就是最大窗口長(zhǎng)度)
          ?????*
          ?????* @param s
          ?????* @return
          ?????*/

          ????public?int?lengthOfLongestSubstringTwoDistinct(String s)?{
          ????????final int?length = s.length();
          ????????final int[] map?= new?int[128];
          ????????int?right = 0, left = 0;
          ????????//count 為不同字符的數(shù)量
          ????????for?(int?count = 0; right < length; ) {
          ????????????//右側(cè)新字符進(jìn)入窗口
          ????????????if?(map[s.charAt(right++)]++ == 0) {
          ????????????????count++;
          ????????????}
          ????????????//如果新字符進(jìn)入窗口后使得 不同字符數(shù)量大于2,則左側(cè)窗口也向右滑動(dòng)一個(gè)(窗口平移)
          ????????????if?(count > 2) {
          ????????????????if?(--map[s.charAt(left++)] == 0) {
          ????????????????????count--;
          ????????????????}
          ????????????}
          ????????}
          ????????return?right - left;
          ????}


          執(zhí)行耗時(shí):4 ms,擊敗了 85.81% 的Java用戶
          內(nèi)存消耗:36.8 MB,擊敗了 96.08% 的Java用戶
          時(shí)間復(fù)雜度:O(n) -- 字符串的遍歷 O(n),哈希表的查詢 O(1)
          空間復(fù)雜度:O(1) -- 定長(zhǎng)的哈希表 O(1),雙指針 O(1)

          好了,今天的文章就到這里,如果覺得有所收獲,請(qǐng)順手點(diǎn)個(gè)在看或者轉(zhuǎn)發(fā)吧,你們的支持是我最大的動(dòng)力。

          上期推文:

          LeetCode1-140題匯總,希望對(duì)你有點(diǎn)幫助!
          LeetCode刷題實(shí)戰(zhàn)141:環(huán)形鏈表
          LeetCode刷題實(shí)戰(zhàn)142:環(huán)形鏈表 II
          LeetCode刷題實(shí)戰(zhàn)143:重排鏈表
          LeetCode刷題實(shí)戰(zhàn)144:二叉樹的前序遍歷
          LeetCode刷題實(shí)戰(zhàn)145:二叉樹的后序遍歷
          LeetCode刷題實(shí)戰(zhàn)146:LRU 緩存機(jī)制
          LeetCode刷題實(shí)戰(zhàn)147:對(duì)鏈表進(jìn)行插入排序
          LeetCode刷題實(shí)戰(zhàn)148:排序鏈表
          LeetCode刷題實(shí)戰(zhàn)149:直線上最多的點(diǎn)數(shù)
          LeetCode刷題實(shí)戰(zhàn)150:逆波蘭表達(dá)式求值
          LeetCode刷題實(shí)戰(zhàn)151:翻轉(zhuǎn)字符串里的單詞
          LeetCode刷題實(shí)戰(zhàn)152:乘積最大子數(shù)組
          LeetCode刷題實(shí)戰(zhàn)153:尋找旋轉(zhuǎn)排序數(shù)組中的最小值
          LeetCode刷題實(shí)戰(zhàn)154:尋找旋轉(zhuǎn)排序數(shù)組中的最小值 II
          LeetCode刷題實(shí)戰(zhàn)155:最小棧
          LeetCode刷題實(shí)戰(zhàn)156:上下翻轉(zhuǎn)二叉樹
          LeetCode刷題實(shí)戰(zhàn)157:用 Read4 讀取 N 個(gè)字符
          LeetCode刷題實(shí)戰(zhàn)158:用 Read4 讀取 N 個(gè)字符 II


          瀏覽 71
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人18毛片A级毛片 | 欧美亚洲及日本黄色电影 | 香蕉视频69 | 免费一级a毛一级a看免费视频下载 | 99热6在线观看 |