【leetcode】14. 最长公共前缀

我的解法

暴力法(垂直扫描法)

求得字符串长度的最小值,最长公共前缀的长度一定不会超过这个最小值 minLen
从第一个字符串依次取 minLen 个字符,每取一个字符就看其余字符串的同一位置是否是该字符,若所有字符串的同一位置都是该字符,将其加入到结果串 com 中,否则,退出循环,该字符前面的部分即为最大前缀串。
在这里插入图片描述

class Solution {
    public String longestCommonPrefix(String[] strs) {
        String com = "";
        int minLen = 200;

        for(int i = 0;i < strs.length;++i)
            minLen = strs[i].length() < minLen ? strs[i].length() : minLen;

        for(int i = 0;i < minLen;++i){
            char tmp = strs[0].charAt(i);
            
            int j;
            for(j = 0;j < strs.length;++j)
                if(strs[j].charAt(i) != tmp)
                    break;
            if(j == strs.length)
                com += tmp;
            else
                break;
        }

        return com;
    }
}

看思路自己实现

水平扫描法

在这里插入图片描述
假设第一个字符串为结果串,用结果串和后续的字符串依次比较,后续的字符串不是以 com 为前缀,则结果串长度减一,直至结果串为所有后续字符串的前缀或者返回 ""
若字符串 comstr 的前缀,则 str.indexOf(com) == 0

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length == 0)
            return "";
            
        String com = strs[0];
        for(int i = 1;i < strs.length;++i){
            while(strs[i].indexOf(com) != 0){
                com = com.substring(0,com.length()-1);
                if(com.length() == 0)
                    return "";
            }
        }

        return com;
    }
}

时间复杂度 : O ( n 2 ) O(n^2) O(n2)

字典序

字典序这个点没有想到,排成字典序,第一个和最后一个的公共前缀就是这个字符串组的最大公共前缀

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


        Arrays.sort(strs,new Cmp());
        String com = strs[0];
        
        //当有多个最短字符串,则都需要比较
        int i = 1;
        while(i != strs.length && strs[i].length() == strs[0].length()){
            while(strs[i].indexOf(com) != 0){
                com = com.substring(0,com.length()-1);
            }
            i++;
        }

        //当有多个最长字符串
        int j = strs.length-2;
        while(j != 0 && strs[j].length() == strs[strs.length-1].length()){
            while(strs[j].indexOf(com) != 0){
                com = com.substring(0,com.length()-1);
            }

            j--;
        }

        for(int k = 0;k < strs.length;++k)
            while(strs[k].indexOf(com) != 0){
                com = com.substring(0,com.length()-1);
                if(com.length() == 0)
                    return "";
            }
        
        return com;
    }
}

class Cmp implements Comparator<String>{
 
	@Override
	public int compare(String o1, String o2) {
		// TODO 自动生成的方法存根
		return o1.length() - o2.length();
	}
}

在这里插入图片描述
。。。。。。终于是过了,仔细想了下,字典序行不通,像 ["baab","bacb","b","cbc"] 这个示例,排序后 ["b","cbc","baab","bacb"],最后还得用水平扫描补一下。

java排序补充

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

private List<Type> list = new ArrayList<>();

Collections.sort(list, new Comparator<Type>() {
            @Override
            public int compare(Type o1, Type o2) {
                return o1.compareTo(o2);//  o1>o2
            }
        });
//倒序排列
Collections.reverse(list);

题解

二分查找法

第一次见这么用,记下来:也是垂直扫描的改进,对于不匹配的情况,只需要原来一般时间就可以扫描到。

由于最长公共前缀不会超过最短的字符串长度 m i n L e n minLen minLen ,所以,只需要在 [ 0 , m i n L e n ] [0,minLen] [0,minLen] 中判断最短公共前缀。

而对于 m i n L e n minLen minLen 长度的字符串,用二分查找,折半查找可以更快的找到失配字符。
每次取查找范围的中间值 m i d mid mid,判断每个字符串的长度为 m i d mid mid 的前缀是否相同,

  • 如果相同则最长公共前缀的长度一定大于或等于 m i d mid mid
  • 如果不相同则最长公共前缀的长度一定小于 m i d mid mid
class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        int minLength = Integer.MAX_VALUE;
        for (String str : strs) {
            minLength = Math.min(minLength, str.length());
        }
        int low = 0, high = minLength;
        while (low < high) {
            int mid = (high - low + 1) / 2 + low;
            if (isCommonPrefix(strs, mid)) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }
        return strs[0].substring(0, low);
    }

    public boolean isCommonPrefix(String[] strs, int length) {
        String str0 = strs[0].substring(0, length);
        int count = strs.length;
        for (int i = 1; i < count; i++) {
            String str = strs[i];
            for (int j = 0; j < length; j++) {
                if (str0.charAt(j) != str.charAt(j)) {
                    return false;
                }
            }
        }
        return true;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

分治法

使用分治法得到字符串数组中的最长公共前缀。

L C P ( S 1 , . . . , S n ) = L C P ( L C P ( S 1 , . . . , S k ) , L C P ( S k + 1 , S n ) ) LCP(S_1,...,S_n) = LCP(LCP(S_1,...,S_k),LCP(S_{k+1},S_n)) LCP(S1,...,Sn)=LCP(LCP(S1,...,Sk),LCP(Sk+1,Sn))

在这里插入图片描述
垂直扫描法的改进。

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

    public String longestCommonPrefix(String[] strs, int start, int end) {
        if (start == end) {
            return strs[start];
        } else {
            int mid = (end - start) / 2 + start;
            String lcpLeft = longestCommonPrefix(strs, start, mid);
            String lcpRight = longestCommonPrefix(strs, mid + 1, end);
            return commonPrefix(lcpLeft, lcpRight);
        }
    }

    public String commonPrefix(String lcpLeft, String lcpRight) {
        int minLength = Math.min(lcpLeft.length(), lcpRight.length());       
        for (int i = 0; i < minLength; i++) {
            if (lcpLeft.charAt(i) != lcpRight.charAt(i)) {
                return lcpLeft.substring(0, i);
            }
        }
        return lcpLeft.substring(0, minLength);
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间复杂度 O ( m n ) O(mn) O(mn)

问题

没想到字典序,还是刷题基础不牢,像位运算,回文串,排序,查找这些基础没练习过,需要从简单的入手,练好基础再来刷这些题就不止 O ( n 2 ) O(n^2) O(n2)

分治法其实很常用,一看到二分查找就想能不能用分治。以后记住,一组数据一定可以两个两个处理或者一半一半处理。

感受就是做好一道题比多做几道简单题有用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AmosTian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值