• Leetcode之最长公共前缀


    问题描述

    编写一个函数来查找字符串数组中的最长公共前缀。

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

    示例 1:

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

    示例 2:

    输入: ["dog","racecar","car"]
    输出: ""
    解释: 输入不存在公共前缀。

    说明:
    所有输入只包含小写字母 a-z 。

    解法

    先取第一个字符串作为起始公共前缀,之后不断取交集。

    class Solution {
        public String longestCommonPrefix(String[] strs) {
            if(strs.length<=0)
        		return "";
        	String str=strs[0];
        	for(String t:strs) {
        		for(int i=0;i<str.length();i++) {
        			if(t.length()>i) {
        				if(t.charAt(i)!=str.charAt(i)) {//字符不相同
        					str=str.substring(0,i);
        					break;
        				}
        			}else if(t.length()==i){//所有字符都相同
        				str=t;
        				break;
        			}else {
        				break;
        			}
        		}
        	}
        	return str;
        }
    }
    

    结果

    {{uploading-image-301830.png(uploading...)}}

    官方解法

    方法一 横向扫描

    用 LCP(S1…Sn) 表示字符串 S1…Sn的最长公共前缀。
    可以得到以下结论:
    LCP(S1…Sn)=LCP(LCP(LCP(S1,S2),S3),…Sn)
    基于该结论,可以得到一种查找字符串数组中的最长公共前缀的简单方法。依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。
    如果在尚未遍历完所有的字符串时,最长公共前缀已经是空串,则最长公共前缀一定是空串,因此不需要继续遍历剩下的字符串,直接返回空串即可。

    class Solution {
        public String longestCommonPrefix(String[] strs) {
            if (strs == null || strs.length == 0) {
                return "";
            }
            String prefix = strs[0];
            int count = strs.length;
            for (int i = 1; i < count; i++) {
                prefix = longestCommonPrefix(prefix, strs[i]);
                if (prefix.length() == 0) {
                    break;
                }
            }
            return prefix;
        }
    
        public String longestCommonPrefix(String str1, String str2) {
            int length = Math.min(str1.length(), str2.length());
            int index = 0;
            while (index < length && str1.charAt(index) == str2.charAt(index)) {
                index++;
            }
            return str1.substring(0, index);
        }
    }
    

    方法二:纵向扫描

    方法一是横向扫描,依次遍历每个字符串,更新最长公共前缀。另一种方法是纵向扫描。纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,如果不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。

    class Solution {
        public String longestCommonPrefix(String[] strs) {
            if (strs == null || strs.length == 0) {
                return "";
            }
            int length = strs[0].length();
            int count = strs.length;
            for (int i = 0; i < length; i++) {
                char c = strs[0].charAt(i);
                for (int j = 1; j < count; j++) {
                    if (i == strs[j].length() || strs[j].charAt(i) != c) {
                        return strs[0].substring(0, i);
                    }
                }
            }
            return strs[0];
        }
    }
    

    方法三 分治

    注意到 LCP的计算满足结合律,有以下结论:
    LCP(S1…Sn)=LCP(LCP(S1…Sk),LCP(Sk+1…Sn))
    其中 LCP(S1…Sn) 是字符串 S1…SnS_1的最长公共前缀,1<k<n1 < k < n1<k<n。
    基于上述结论,可以使用分治法得到字符串数组中的最长公共前缀。对于问题 LCP(Si⋯Sj)可以分解成两个子问题 LCP(Si…Smid)与 LCP(Smid+1…Sj),其中 mid=(i+j)/2.对两个子问题分别求解,然后对两个子问题的解计算最长公共前缀,即为原问题的解。

    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);
        }
    }
    

    方法四 二分查找

    显然,最长公共前缀的长度不会超过字符串数组中的最短字符串的长度。用 minLength 表示字符串数组中的最短字符串的长度,则可以在 [0,minLength][0,minLength}][0,minLength] 的范围内通过二分查找得到最长公共前缀的长度。每次取查找范围的中间值 mid,判断每个字符串的长度为 mid 的前缀是否相同,如果相同则最长公共前缀的长度一定大于或等于 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;
        }
    }
    
  • 相关阅读:
    php
    nginx
    docker
    pyenv 配置python虚拟环境
    [运维笔记] Nginx编译安装
    [运维笔记] Mysql单库备份脚本
    BurpSuite Intruder 4种攻击模式
    java判断一个单向链表是否有环路
    二分查找(递归和非递归)
    反转链表算法题
  • 原文地址:https://www.cnblogs.com/code-fun/p/13656302.html
Copyright © 2020-2023  润新知