【Leetcode】【簡單】【14最長公共前綴】【JavaScript】


題目

14. 最長公共前綴

編寫一個函數來查找字符串數組中的最長公共前綴。

如果不存在公共前綴,返回空字符串 ""

示例 1:

輸入: ["flower","flow","flight"]
輸出: "fl"

示例 2:

輸入: ["dog","racecar","car"]
輸出: ""
解釋: 輸入不存在公共前綴。

說明:

所有輸入只包含小寫字母 a-z 。

解答

解答一:兩層for循環

誤區1:剛開始考慮了先數組元素遍歷,然后再元素(字符串)從頭到尾比較,但實際上要先以第一個元素strs[0]為基准。

漏洞1:沒有考慮strs元素為空字符串的情況,如[""],未考慮連續元素都相等的情況如["c","c"],結果這些在提交時都是要判斷的。

個人思路:

1、若傳入為空數組[]或空字符串[""]則直接返回空字符串;

2、取傳入數組的第一個元素為基准字符串,並聲明common數組,用於存放公共前綴;

3、第一層i循環(可以想像指針指向strs[0],且從strs[0][0]往str[0][1、2、3…]移動)第二層j循環(可以想像指針指向strs[1],且從strs[1]往str[2、3…]移動),即題中"flower"中的"f",與"flow"中的"f"相比較;

4、相同則j自增,即"flower"中的"f"繼續與"flight"中的"f"比較;

5、若j循環未徹底完成,即說明當前的str[i]已經不是公共前綴了,就可以返回common了;若此次j循環徹底完成,則將當前的str[i],push進common;

6、外層的i循環結束后,若未觸發過j循環內的return的話,類似["a","a","a"]["ab","abc","abcd"]等等情況的,直接返回strs[0],即str即可。

代碼如下:(已在leetcode提交通過,執行用時104ms)

var longestCommonPrefix = function(strs) {
    if (strs.length===0 ||strs[0].length===0){return "";}      
    var str=strs[0],                                
        common=[];                                  
    for(let i=0,len1=str.length;i<len1;i++){        
        for(let j=1,len2=strs.length;j<len2;j++){   
            if(str[i]!==strs[j][i]){                 
                return common.join("");
            }
        }
        common.push(str[i]);
    }return str;
};

 兩層循環示意圖如下:

(GIF)

 

解答二:水平掃描法

參考平台提供題解,提供的第一種方法是“水平掃描法”:

仍然是先把數組中第一個元素str取出來,然后以這個元素為基准,

使用stringObject.indexOf(searchvalue,fromindex)方法查找,

查一下str是否在strs[i]索引為0的位置,

如果不在索引為0的位置,使用stringObject.substring(start,stop)刪減字符串長度,

把str長度減1,再繼續查,直到str長度減到0為止。

代碼如下:(已在leetcode提交通過,執行用時100ms)

var longestCommonPrefix = function(strs) {
    if (strs.length===0 ||strs[0].length===0){return "";}
    var str=strs[0];
    for (let i=1,len=strs.length;i<len;i++){
        while(strs[i].indexOf(str)!==0) {
            if (str.length === 0) {return "";}
            str = str.substring(0, str.length - 1);
        }
    }return str;
}
 public String longestCommonPrefix(String[] strs) {
    if (strs.length == 0) return "";
    String prefix = strs[0];
    for (int i = 1; i < strs.length; i++)
        while (strs[i].indexOf(prefix) != 0) {
            prefix = prefix.substring(0, prefix.length() - 1);
            if (prefix.isEmpty()) return "";
        }        
    return prefix;
}
 
平台提供 Java 實現代碼

平台提供示意圖如下:

14最長公共前綴水平掃描法示意圖

解答三:水平掃描法(改良)

參考平台提供題解,水平掃描法有改良版,

不是取數組第一個元素,還是直接取該元素中的單獨字符,類似本頁中第一種方法,兩個for循環,代碼稍有區別。

首先第一層for循環(枚舉首個字符串的所有字符),使用stringObject.charAt(index)方法獲取數組第一個元素的第i個字符,賦值給c,

第二層for循環,從索引1開始遍歷數組中所有剩余元素的對應i位置的字符,並與c比較,

如果該字符不等於c,或者壓根沒有該字符,直接使用stringObject.substring(start,stop)方法返回首個元素從索引0到i的拷貝,

若兩層循環都正常運行過,未觸發返回,則是類似["ab","abc","abcd"]["aa",aaa"","aaaaa"]這些情況,即第一個元素最短,且整體都符合條件,此時返回這個元素即可。

代碼如下:(已在leetcode提交通過,執行用時92ms)

var longestCommonPrefix = function(strs) {
    if (strs.length===0 ||strs[0].length===0){return "";}
    for (let i=0,len1=strs[0].length;i<len1;i++){
        let c=strs[0].charAt(i);
        for (let j=1,len2=strs.length;j<len2;j++){
            if(i===strs[j].length||strs[j].charAt(i)!==c){
                return strs[0].substring(0,i);
            }
        }
    }return strs[0];
}

解答四:分治

/**2019.03.11 01:40更新

*/

 

繼續參考平台提供題解,算法三:分治

大致意思是把數組拆分成左右兩部分,循環拆(遞歸?),直至最后一層的左右兩部分都只有一個元素,

然后將這最后一層的兩個元素進行比較,看是否有公共前綴,結果返回上一層,繼續比較,最后到頂層;

仿照題解,我定義了三個函數,第一個是該題解要運行的函數longestCommonPrefix()第二個是拆分函數divide()第三個是比較函數compare();

longestCommonPrefix()返回divide()函數,並傳入strs數組和該數組的索引起始、結束位置;

longestCommonPrefix()代碼如下:

var longestCommonPrefix = function(strs) {
    if (strs.length===0 ||strs[0].length===0){return "";}
    return divide(strs,0,strs.length-1);
}

divide(strs,l,r)接收三個參數,strs:傳入的數組;l(left):要拆分部分在strs中索引的開始位置;r(right):要拆分部分在strs中索引的結束位置;

divide()中,首先判斷傳入參數的l和r,如果相等,即是開始位置與結束位置相同,該函數返回這個元素;

如果l不等於r,即數組還沒拆到最后一層,把l和r求和后平分,向下取整,作為l和r的中點索引位置mid,然后中點前后兩部分繼續調用divide(),直至這兩部分都返回一個元素;

divide()代碼如下:

function divide(strs,l,r){
    if(l===r){
        return strs[l];
    }else{
        let mid=Math.floor((l+r)/2);
        let leftPre=divide(strs,l,mid),
            rightPre=divide(strs,mid+1,r);
        return compare(leftPre,rightPre);
    }
}

接着調用compare(),這個函數用來比較並找出這兩個元素(字符串)的公共前綴,並將這個前綴返回至上一層和上層的另一部分返回的前綴繼續比較;

依此類推,直到頂層,得出所有元素的最長公共前綴;

這里使用的方法和上個解答一致,兩個, stringObject.substring(start,stop)stringObject.charAt(index)

compare()代碼如下:

function compare(left,right){
    let min=Math.min(left.length,right.length);
    for(let i=0;i<min;i++){
        if(left.charAt(i) !== right.charAt(i)){
            return left.substring(0,i);
        }
    }return left.substring(0,min);
}

完整代碼如下:(已在leetcode提交通過,執行用時108ms)

var longestCommonPrefix = function(strs) {
    if (strs.length===0 ||strs[0].length===0){return "";}
    return divide(strs,0,strs.length-1);
}
function divide(strs,l,r){
    if(l===r){
        return strs[l];
    }else{
        let mid=Math.floor((l+r)/2);
        let leftPre=divide(strs,l,mid),
            rightPre=divide(strs,mid+1,r);
        return compare(leftPre,rightPre);
    }
}
function compare(left,right){
    let min=Math.min(left.length,right.length);
    for(let i=0;i<min;i++){
        if(left.charAt(i) !== right.charAt(i)){
            return left.substring(0,i);
        }
    }return left.substring(0,min);
}
完整代碼

平台提示意圖如下:

圖 2. 查找最長公共前綴的分治方法

說下自己碰到的,題解里面,這個"l"搞得像個阿拉伯數字"1",在這里浪費了不少時間,🤦‍♂️,還是太嫩,希望你們別踩坑。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM