代碼隨想錄算法訓(xùn)練營(yíng)Day02 | LeetCode977 有序數(shù)組的平方、LeetCode209 長(zhǎng)度最小的子數(shù)組、LeetCode59 螺旋矩陣II

今日學(xué)習(xí)的視頻和文章

  • 代碼隨想錄 有序數(shù)組的平方
  • 代碼隨想錄 長(zhǎng)度最小的子數(shù)組
  • 代碼隨想錄 螺旋矩陣
  • @YouLookDeliciousC 的題解:54. 螺旋矩陣 - 力扣(Leetcode)

LeetCode977 有序數(shù)組的平方

977. 有序數(shù)組的平方 - 力扣(Leetcode)

  • 初見題目的想法

    • 一開始我想的是設(shè)置一個(gè)left指針和一個(gè)right指針脊串,從數(shù)組“中間”開始向兩邊比較辫呻。這個(gè)邏輯是錯(cuò)誤的,應(yīng)該是找到平方值最小的那個(gè)元素的位置作為雙指針的起始位置琼锋,而不是取數(shù)組的“中間”印屁。

    • 那么,應(yīng)該遍歷一遍數(shù)組斩例,找到合適的起始位置雄人。變量尋找合適的起始位置的代碼如下

    • int n = nums.size();
      vector<int> res;
      
      int start = 0;
      int curPowMin = pow(nums[start], 2);
      for (int i = 1; i < n; i++) {
          if (pow(nums[i], 2) < curPowMin) {
              curPowMin = pow(nums[i], 2);
              start = i;
          }
      }
      int left = start;
      int right = start + 1;
      
    • 找到合適的起始位置后,用leftright分別向左和向右取數(shù)組元素念赶,比較平方值础钠,將平方值較小的元素放入答案數(shù)組中。

    • while (0 <= left || right < n) {
          int powLeft = 0 <= left ? pow(nums[left], 2) : INT_MAX;
          int powRight = right < n ? pow(nums[right], 2) : INT_MAX;
          if (powLeft < powRight) {
              res.push_back(powLeft);
              left--;
          }
          else {
              res.push_back(powRight);
              right++;
          }
      }
      

完整題解代碼如下:

vector<int> sortedSquares(vector<int>& nums) {
    int n = nums.size();
    vector<int> res;

    int start = 0;
    int curPowMin = pow(nums[start], 2);
    for (int i = 1; i < n; i++) {
        if (pow(nums[i], 2) < curPowMin) {
            curPowMin = pow(nums[i], 2);
            start = i;
        }
    }
    int left = start;
    int right = start + 1;

    while (0 <= left || right < n) {
        int powLeft = 0 <= left ? pow(nums[left], 2) : INT_MAX;//三目表達(dá)式防止下標(biāo)越界
        int powRight = right < n ? pow(nums[right], 2) : INT_MAX;
        if (powLeft < powRight) {
            res.push_back(powLeft);
            left--;
        }
        else {
            res.push_back(powRight);
            right++;
        }
    }

    return res;
}

分別遍歷了兩次數(shù)組叉谜,時(shí)間復(fù)雜度應(yīng)為O(n)旗吁。

  • 看了代碼隨想錄講解后自己的一些體會(huì)

以前寫題的時(shí)候也看過代碼隨想錄的講解,感覺比大學(xué)課堂里的講解清楚很多停局。最近考研復(fù)習(xí)也在復(fù)習(xí)高數(shù)很钓,所以聯(lián)想到了二次函數(shù)的圖像,最小的平方值相對(duì)來說在數(shù)組的“中間”董栽,最大的平方值相對(duì)來說在數(shù)組的“兩邊”码倦。既然要比較“兩邊”誰大誰小,自然就想到了雙指針來向兩邊取元素锭碳。

不過我自己寫的方法和代碼隨想錄里的比起來還是不夠簡(jiǎn)潔袁稽,我的方法里“找起始位置“這一步,其實(shí)是沒有必要的擒抛。只需要讓left從最左邊開始推汽,right從最右邊開始,將平方值較大的數(shù)歧沪,從答案數(shù)組的最大下標(biāo)向最小下標(biāo)開始填充就可以了歹撒。

改良后的題解代碼如下,甚至可以用三目表達(dá)式一條語句搞定诊胞。

vector<int> sortedSquares(vector<int>& nums) {
    int n = nums.size();
    vector<int> res(n);
    for (int l = 0, r = n - 1, k = r; l <= r; ) {
        res[k--] = pow(nums[l], 2) > pow(nums[r], 2) ? 
                pow(nums[l++], 2) : pow(nums[r--], 2);
    }
    return res;
}

LeetCode209 長(zhǎng)度最小的子數(shù)組

209. 長(zhǎng)度最小的子數(shù)組 - 力扣(Leetcode)

  • 初見題目時(shí)的想法
    • left保存子數(shù)組在原數(shù)組中的起始下標(biāo)暖夭,用right保存子數(shù)組在原數(shù)組中的結(jié)束下標(biāo)。
    • right先向右移動(dòng)厢钧,如果出現(xiàn)了[left, right]的子數(shù)組的元素之和大于等于target鳞尔,就讓left向右移動(dòng),然后讓right繼續(xù)向右移動(dòng)早直,繼續(xù)尋找元素之和大于等于target的連續(xù)子數(shù)組寥假。
    • 然后我就在邊界條件的調(diào)試上卡了很久,最后還是直接看講解了霞扬。
  • 看了講解之后的體會(huì):
    • 外層循環(huán)的邊界條件一定是right移動(dòng)到右邊界糕韧,如果是left移動(dòng)到右邊界的話就和暴力解法沒有區(qū)別了枫振。我自己做題的時(shí)候一直沒有明確這一點(diǎn),還在考慮left == rightright移動(dòng)到右邊界的情況萤彩,實(shí)際上這和滑動(dòng)窗口的思想就矛盾了粪滤。

完整題解代碼如下

int minSubArrayLen(int target, vector<int>& nums) {
    int n = nums.size();
    int res = INT_MAX;

    int l = 0;
    int r = 0;
    int sum = 0;
    while (r < n) {
        sum += nums[r];
        while (sum >= target) {
            res = min(res, r - l + 1);
            sum -= nums[l++];
        }
        r++;
    }

    return res == INT_MAX ? 0 : res;
}
  • 這題卡了比較久,還是要橙阜觯回頭看杖小,并且多練類似思想的題目。
  • 另外還鬧了個(gè)烏龍愚墓,這題是在外面聽講座的時(shí)候做的予权,讀題目時(shí),電腦開了節(jié)電模式浪册,沒看清要求是”大于等于 target“而不是”等于 target“扫腺。這種細(xì)節(jié)問題也是要注意的,如果代碼邏輯對(duì)了村象,但是還是不能AC笆环,那可能就要看看自己是不是看錯(cuò)題目了……

LeetCode59 螺旋矩陣II

59. 螺旋矩陣 II - 力扣(Leetcode)

  • 初見題目時(shí)的想法

  • 按照循環(huán)不變量原則,我在這里記錄一下自己的體會(huì):

    • 首先是如何定義螺旋籍救,代碼隨想錄里是這樣定義的(如圖):

      • image.png
      • 每條邊都是一個(gè)左閉右開區(qū)間习绢,對(duì)于方陣而言,這是非常清晰蝙昙、明確的“螺旋”的定義。但是我在寫 LeetCode54 題時(shí)梧却,繼續(xù)按照這個(gè)定義去處理“螺旋”奇颠,就碰到了很多邊界條件的問題。

      • 因?yàn)?LeetCode54 并沒有限制矩陣是方陣放航,按照左閉右開區(qū)間的定義烈拒,在處理只有一行或者一列的矩陣的時(shí)候,就會(huì)出現(xiàn)一些奇怪的情況广鳍,因?yàn)樽箝]右開區(qū)間荆几,在矩陣只剩一行或一列的還沒被訪問的時(shí)候,就有可能出現(xiàn)因?yàn)閰^(qū)間右邊不能取等號(hào)而遺漏元素的情況赊时。

      • 以下是我磕磕絆絆修修補(bǔ)補(bǔ)才通過的 LeetCode54 的代碼

      • class Solution {
        public:
            vector<int> spiralOrder(vector<vector<int>>& matrix) {
                vector<int> result;
                int rowNum = matrix.size();
                int colNum = matrix[0].size();
                int sumNum = rowNum * colNum;
                int x = 0;
                int y = 0;
                int loop = rowNum / 2;
                int count = 1;
                while(count <= loop) {
                    for (; x < colNum - count; x++) {
                        result.push_back(matrix[y][x]);
                        if(result.size() == sumNum) return result;
                    }
                    
                    for (; y < rowNum - count; y++) {
                        result.push_back(matrix[y][x]);
                        if(result.size() == sumNum) return result;
                    }
                    if(result.size() == sumNum) return result;
                    
                    for (; x >= count; x--) {
                        result.push_back(matrix[y][x]);
                        if(result.size() == sumNum) return result;
                    }
                    
                    for (; y >= count; y--) {
                        result.push_back(matrix[y][x]);
                        if(result.size() == sumNum) return result;
                    }
                    if(result.size() == sumNum) return result;
                                
                    count++;
                    x++;
                    y++;
                }
        
                if (rowNum <= colNum) {
                    for (; x <= colNum - count; x++) {
                        result.push_back(matrix[y][x]);
                        if(result.size() == sumNum) return result;
                    }
                }
        
                if (rowNum > colNum) {
                    for (; y <= rowNum - count; y++) {
                        result.push_back(matrix[y][x]);
                        if(result.size() == sumNum) return result;
                    }
                }
        
                return result;
            }
        };
        
  • 所以吨铸,在堅(jiān)持循環(huán)不變量原則的同時(shí),如何找或者說如何去定義循環(huán)不變量也影響我們?nèi)绾稳懘a祖秒。如果我們這樣去定義“螺旋”诞吱,所有區(qū)間都取閉區(qū)間舟奠,就可以避免一些由于開區(qū)間而導(dǎo)致的邊界條件判斷。

    1. 從左到右訪問完矩陣的第一行房维,然后重新定義上邊界沼瘫,體現(xiàn)在代碼上就是矩陣的“上邊界”+1。
    2. 判斷上下邊界是否交錯(cuò)即(上邊界 > 下邊界)咙俩。
    3. 從上到下訪問完矩陣的最后一列耿戚,然后重新定義右邊界,體現(xiàn)在代碼上就是矩陣的“右邊界”-1阿趁。
    4. 判斷左右邊界是否交錯(cuò)即(左邊界 > 右邊界)溅话。
    5. 從右到左訪問完矩陣的最后一行,然后重新定義下邊界歌焦,體現(xiàn)在代碼上就是矩陣的“下邊界”-1飞几。
    6. 判斷左右邊界是否交錯(cuò)即(左邊界 > 右邊界)。
    7. 從下到上訪問完矩陣的第一列独撇,然后重新定義左邊界屑墨,體現(xiàn)在代碼上就是矩陣的“左邊界”+1。
    8. 判斷上下邊界是否交錯(cuò)即(上邊界 > 下邊界)纷铣。
    9. 不斷重復(fù)以上步驟卵史,直到左右邊界交錯(cuò)或者上下邊界交錯(cuò)。
  • 為什么這樣做可以所有的區(qū)間都只用閉區(qū)間來定義“螺旋”呢搜立?按照之前提到左閉右開的定義以躯,我們對(duì)于“螺旋”的定義是靜態(tài)的,沒有考慮每訪問一條邊之后矩陣的變化啄踊。而按照 @YouLookDeliciousC 的方法忧设,對(duì)于“螺旋”的定義是動(dòng)態(tài)的,考慮了每訪問一條邊之后矩陣的變化颠通,從而能只用閉區(qū)間來定義“螺旋”址晕。

IMG_20230406_210212.jpg

LeetCode59 完整的題解代碼如下:

vector<vector<int>> generateMatrix(int n) {
    vector<vector<int>> res(n, vector<int>(n));
    int top = 0;
    int bottom = n - 1;
    int left = 0;
    int right = n - 1;

    int count = 1;
    while (count <= n * n) {
        for (int x = left, y = top; x <= right; x++) {
            res[y][x] = count++; 
        }
        if (++top > bottom) break;

        for (int x = right, y = top; y <= bottom; y++) {
            res[y][x] = count++;
        }
        if (--right < left) break;

        for (int x = right, y = bottom; x >= left; x--) {
            res[y][x] = count++;
        }
        if (--bottom < top) break;

        for (int x = left, y = bottom; y >= top; y--) {
            res[y][x] = count++;
        }
        if (++left > right) break;
    }

    return res;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市顿锰,隨后出現(xiàn)的幾起案子谨垃,更是在濱河造成了極大的恐慌,老刑警劉巖硼控,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刘陶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡牢撼,警方通過查閱死者的電腦和手機(jī)匙隔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浪默,“玉大人牡直,你說我怎么就攤上這事缀匕。” “怎么了碰逸?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵乡小,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我饵史,道長(zhǎng)满钟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任胳喷,我火速辦了婚禮湃番,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吭露。我一直安慰自己吠撮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布讲竿。 她就那樣靜靜地躺著泥兰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪题禀。 梳的紋絲不亂的頭發(fā)上鞋诗,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音迈嘹,去河邊找鬼削彬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛秀仲,可吹牛的內(nèi)容都是我干的融痛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼啄育,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼酌心!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起挑豌,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎墩崩,沒想到半個(gè)月后氓英,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹦筹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年铝阐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铐拐。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡徘键,死狀恐怖练对,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吹害,我是刑警寧澤螟凭,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站它呀,受9級(jí)特大地震影響螺男,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纵穿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一下隧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谓媒,春花似錦淆院、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宗弯,卻和暖如春脯燃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蒙保。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工辕棚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邓厕。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓逝嚎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親详恼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子补君,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容