记录五——最长相同前缀

最长相同前缀

写一个函数,在一个字符串数组中找出最长的相同前缀字符串,如果没有相同前缀,返回一个空字符串“”。
例:input: [“flower”,“flow”,“flight”] output:“fl”
input:[“dog”,“racecar”,“car”] output:""
我的思路:因为要找出数组中所有元素的公共最长子串,所以必要遍历所有的元素,然而,数组中的每个元素都是字符串,对字符串的判断遍历每个字符,双层循环可以得到最长的公共子串。遍历数组的同时分别比较每个元素的字符。这种方法叫“垂直扫描”
代码

class Solution {
   	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);
	        for (int j = 1; j < strs.length; j ++) {
	            if (i == strs[j].length() || strs[j].charAt(i) != c)//注意防止溢出异常
	                return strs[0].substring(0, i);             
	        }
         return strs[0];
    }
}

时间复杂度:O(S),空间复杂度:O(1)

看了解析后,发现还有另外的方法:水平扫描,分治法,二分法。

  • 水平扫描:拿本题为例,将第一个元素strs[0]作为基本元素,分别与数组中其它的每个元素进行比较找出共同的前缀。下面沾上图:

在这里插入图片描述

  • 分治法:将问题简单化,因为本题设计到多个元素,首先考虑到比较两个字符串的最长前缀是比较简答的一个事情,因此可将数组进行划分,递归的求出公共最长子串
    下面直接粘过来代码:
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);
}

时间复杂度:O(S),空间复杂度:O(m·log(n))

  • 二分法:因为是找最长公共前缀,所以首先可以找出数组中长度最短的元素,最长公共前缀肯定是在该元素中。将该元素进行二分法,先抛弃一半进行计算,将生下来的一半字符串与数组中剩余元素进行比较,看是否存在于所有元素中,如果是,则对之前抛弃的那一半再次进行二分法查找进行计算。最后得到最长前缀所处的索引位置,进而得到答案。
    在这里插入图片描述这里粘上代码:
public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0)
        return "";
    int minLen = Integer.MAX_VALUE;
    for (String str : strs)
        minLen = Math.min(minLen, str.length());
    int low = 1;
    int high = minLen;
    while (low <= high) {
        int middle = (low + high) / 2;
        if (isCommonPrefix(strs, middle))
            low = middle + 1;
        else
            high = middle - 1;
    }
    return strs[0].substring(0, (low + high) / 2);
}

private boolean isCommonPrefix(String[] strs, int len){
    String str1 = strs[0].substring(0,len);
    for (int i = 1; i < strs.length; i++)
        if (!strs[i].startsWith(str1))//测试此字符串是否以指定的前缀开始
            return false;
    return true;
}

时间复杂度:O(S·log(n)),空间复杂度:O(1)

出了上述说的方法外,还可以利用树来解决,如下图:
在这里插入图片描述【注】要深刻理解思想,多看API

猜你喜欢

转载自blog.csdn.net/w1375834506/article/details/88089611