Leetcode 14 Longest Common Prefix

weixin_34232744發表於2018-11-17

leetcode.windliang.cc/ 第一時間釋出

題目描述(簡單難度)

解法一 垂直比較

我們把所有字串垂直排列,然後一列一列的比較,直到某一個字串到達結尾或者該列字元不完全相同。

下邊看一下我的程式碼,看起來比較多

//這個函式判斷 index 列的字元是否完全相同
public boolean isSameAtIndex(String[] strs, int index) {
    int i = 0;
    while (i < strs.length - 1) {
        if (strs[i].charAt(index) == strs[i + 1].charAt(index)) {
            i++;
        } else {
            return false;
        }
    }
    return true;
}

public String longestCommonPrefix(String[] strs) {
    if (strs.length == 0)
        return "";
    //得到最短的字串的長度
    int minLength = Integer.MAX_VALUE;
    for (int i = 0; i < strs.length; i++) {
        if (strs[i].length() < minLength) {
            minLength = strs[i].length();
        }
    }
    int j = 0;
    //遍歷所有列
    for (; j < minLength; j++) {
        //如果當前列字元不完全相同,則結束迴圈
        if (!isSameAtIndex(strs, j)) {
            break;
        }
    }
    return strs[0].substring(0, j);

}
複製程式碼

下邊看一下,官方的程式碼

public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0) return "";
    //遍歷所有列
    for (int i = 0; i < strs[0].length() ; i++){
        char c = strs[0].charAt(i); // 儲存 i 列第 0 行的字元便於後續比較
        //比較第 1,2,3... 行的字元和第 0 行是否相等
        for (int j = 1; j < strs.length; j ++) {
            /**
             * i == strs[j].length() 表明當前行已經到達末尾
             * strs[j].charAt(i) != c  當前行和第 0 行字元不相等
             * 上邊兩種情況返回結果
             */
            if (i == strs[j].length() || strs[j].charAt(i) != c)
                return strs[0].substring(0, i);             
        }
    }
    return strs[0];
}
複製程式碼

時間複雜度:最壞的情況就是 n 個 長度為 m 的完全一樣的字串,假設 S 是所有字元的和,那麼 S = m * n,時間複雜度就是 O(S)。當然正常情況下並不需要比較所有字串,最多比較 n * minLen 個字元就可以了。

空間複雜度:O(1),常數個額外空間。

解法二 水平比較

我們將字串水平排列,第 0 個和第 1 個字串找最長子串,結果為 leet,再把結果和第 2 個字串比較,結果為 leet,再把結果和第 3 個字串比較,結果為 lee,即為最終結果。

public String longestCommonPrefix3(String[] strs) {
		if (strs.length == 0)
			return "";
		String prefix = strs[0]; // 儲存結果
		// 遍歷每一個字串
		for (int i = 1; i < strs.length; i++) {
			// 找到上次得到的結果 prefix 和當前字串的最長子串
			int minLen = Math.min(prefix.length(), strs[i].length());
			int j = 0;
			for (; j < minLen; j++) {
				if (prefix.charAt(j) != strs[i].charAt(j)) {
					break;
				}
			}
			prefix = prefix.substring(0, j);
		}
		return prefix;
	}
複製程式碼

時間複雜度:最壞情況和解法一是一樣,n 個長度為 m 的完全相同的字元,就要比較所有的字元 S,S = n * m 。但對於正常情況,處於最短字串前的字串依舊要比較所有字元,而不是最短字串個字元,相對於解法一較差。

空間複雜度:O(1)。

解法三 遞迴

我們把原來的陣列分成兩部分,求出左半部分的最長公共字首,求出右半部分的最長公共字首,然後求出的兩個結果再求最長公共字首,就是最後的結果了。

求左半部分的最長公共字首,我們可以繼續把它分成兩部分,按照上邊的思路接著求。然後一直分成兩部分,遞迴下去。

直到該部分只有 1 個字串,那麼最長公共子串就是它本身了,直接返回就可以了。

public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0) return "";    
        return longestCommonPrefix(strs, 0 , strs.length - 1);
}

//遞迴不斷分成兩部分
private String longestCommonPrefix(String[] strs, int l, int r) {
    if (l == r) {
        return strs[l];
    }
    else {
        int mid = (l + r)/2;
        String lcpLeft =   longestCommonPrefix(strs, l , mid);
        String lcpRight =  longestCommonPrefix(strs, mid + 1,r);
        return commonPrefix(lcpLeft, lcpRight);
   }
}
//求兩個結果的最長公共字首
String commonPrefix(String left,String right) {
    int min = Math.min(left.length(), right.length());       
    for (int i = 0; i < min; i++) {
        if ( left.charAt(i) != right.charAt(i) )
            return left.substring(0, i);
    }
    return left.substring(0, min);
}
複製程式碼

時間複雜度:

空間複雜度:

每次遇到遞迴的情況,總是有些理不清楚,先空著吧。

進行了垂直比較和水平比較,又用到了遞迴,solution 裡還介紹了二分查詢,感覺這裡用二分查詢有些太僵硬了,反而使得時間複雜度變高了。還介紹了字首樹,這裡後邊遇到再總結吧。

相關文章