leetcode爬坑史(一)-- [14] 最長公共字首

海龍獨仙發表於2019-03-22

最近看公眾號推送被安利了一個vscode神器, leetcode 外掛,可以直接在vscode裡編寫程式碼,然後直接提交leetcode 測試,加上可以直接用vscode debug,這樣就可以全程不開啟網頁比較方便的刷題了,作為一個刷題新手,就從最簡單的字串類題目開始吧

題目

/*
* @lc app=leetcode.cn id=14 lang=javascript
*
* [14] 最長公共字首
*
* https://leetcode-cn.com/problems/longest-common-prefix/description/
*
* algorithms
* Easy (31.50%)
* Total Accepted:    57.1K
* Total Submissions: 177K
* Testcase Example:  '["flower","flow","flight"]'
*
* 編寫一個函式來查詢字串陣列中的最長公共字首。
* 
* 如果不存在公共字首,返回空字串 ""。
* 
* 示例 1:
* 
* 輸入: ["flower","flow","flight"]
* 輸出: "fl"
* 
* 
* 示例 2:
* 
* 輸入: ["dog","racecar","car"]
* 輸出: ""
* 解釋: 輸入不存在公共字首。
* 
* 
* 說明:
* 
* 所有輸入只包含小寫字母 a-z 。
* 
*/
/**
* @param {string[]} strs
* @return {string}
*/
複製程式碼

第一想法

看到這個題目,我腦子裡第一時間冒出來了 ES6 的 Set,當時的思路是,遍歷整個陣列.然後遍歷所有字串,將字串的第n位新增到set裡,如果這個set 的長度大於1,迴圈就可以終止,就可以求出結果.然後就開始擼起了程式碼,

第一版如下

 // 遍歷字串, 然後push 到set 裡 哪個set長度為2 即終止
var longestCommonPrefix = function(strs) {
   let len = strs[0].length
   let sets = []
   let x;
   for(let i=0; i<len; i++){
       sets[i] = new Set()
       strs.forEach(item => {
           if (!item[i]){
               return ""
           }
           sets[i].add(item[i])
          
       })
       if (sets[i].size > 1) {
           return strs[0].slice(0, i)
       }
   }
   
};

複製程式碼

本地跑第一個用例通過,興沖沖的點選提交.結果是殘酷的

  • 執行出錯資訊: Line 43: TypeError: Cannot read property 'length' of undefined
  • 最後執行的輸入:[] 呀,沒有考慮到陣列為空的情況,這樣把,加上一個判斷

第二次提交

函式一開始加個判斷

if(!strs[0]){
  return ""
}
複製程式碼

當然也是不通過啦,但是有進步啦,至少這次通過了73個測試用例了

  • 73 / 118 個通過測試用例 狀態:解答錯誤
  • 輸入:["a"]
  • 輸出:undefined
  • 預期:"a"

又沒考慮到邊界情況, 得,再加上個判斷吧

第三次提交

函式開始再加個判斷

if(strs.length === 1){
    return strs[0]
}
複製程式碼

再來, emmm, 進步了一位

  • 74 / 118 個通過測試用例 狀態:解答錯誤
  • 輸入:["c","c"]
  • 輸出:undefined
  • 預期:"c"

難受啊,咋這麼多個奇葩的情況

第四次提交

在函式最後加上預設情況

return strs[0]
複製程式碼

這次前進了30位啦,就差最好16個測試用例就成功啦

  • 102 / 118 個通過測試用例 狀態:解答錯誤
  • 輸入:["aa","a"]
  • 輸出:"aa"
  • 預期:"a"

這個地方卡了好久,我之前有判斷過如果後面的字串長度有小於第一個字串的時候就直接return, 但是為什麼沒生效呢,

if (!item[i]){
    return ""
}
複製程式碼

通過vscode debug 發現,原來return 出了 內層的forEach 之後,外層的for 迴圈居然照樣執行,行吧,那在裡面標記下.如果外層出現了這個標記,就也return出去(中間去搜了下js跳出多重迴圈,但是不知道為什麼都是報錯.不知道網上那些部落格怎麼寫出來的.break,break tag之類的,發現我直接用就報錯,不合法,所以才採用標記位這種方法)

第五次提交

    let x = ''
    for(var i=0; i<len; i++){
        sets[i] = new Set()
        strs.forEach(item => {
            if (!item[i]) {
                x = i
                return strs[0].slice(0, i - 1)
            }
            sets[i].add(item[i])
        })
        // console.log(sets[i])
        if (sets[i].size > 1) {
            return strs[0].slice(0, i)
        }
    }
    if(x) {
        return strs[0].slice(0, i - 1)
    }
    return strs[0
複製程式碼

當然也不期待直接就過了.但是有進步呀,

  • 110 / 118 個通過測試用例 狀態:解答錯誤
  • 輸入:["abab","aba",""]
  • 輸出:"aba"
  • 預期:""

又是沒有考慮到邊界情況,行吧,再加一個標記判斷一下邊界情況

第六次提交

完整程式碼

var longestCommonPrefix = function(strs) {
    if(!strs[0]){
        return ""
    }
    if(strs.length === 1){
        return strs[0]
    }
    let len = strs[0].length
    let sets = []
    let x = ''
    for(var i=0; i<len; i++){
        sets[i] = new Set()
        strs.forEach(item => {
            if(!item){
                x= 'f'
                return 
            }
            if (!item[i]) {
                x = i
                return
            }
            sets[i].add(item[i])
        })
        if(x === 'f'){
            return ""
        }
        if(x) {
            return strs[0].slice(0, i)
        }
        if (sets[i].size > 1) {
            return strs[0].slice(0, i)
        }
    }
    return strs[0]
};
複製程式碼

終於:

  • 118 / 118 個通過測試用例狀態:通過
  • 執行用時:152 ms
  • 擊敗了6.84% JavaScript的提交記錄 感動的哭了,終於通過了.雖然整個解法比較ugly,自己都有點看不過去.但是也是自己的一種思路,一步步的趟過來,也算實現了.

一共花了40分鐘,真不容易啊,這麼簡單的一道題,裡面就隱含著這麼多坑,讓我對後面中等難度及複雜難度有一種未知的恐懼感.Anyway,反正已經開始入坑了,希望自己能堅持下去,儘量抽時間刷一刷題吧.

最後,總結一下,刷題新手從這題得到的經驗是:以後做題,首先閒考慮幾種邊界情況,陣列為空,元素為空,及元素數量少該怎麼處理.這樣就能省好多事,嗯,記錄一下這個心路歷程.好了,去看前面的人的解法去了,研究下,看看別人的解法什麼樣,學習一下

相關文章