14.最长公共前缀

14.最长公共前缀

题目描述

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。(所有输入只包含小写字母 a-z )

官方题解

水平扫描

解题思路:将第一个字符串作为暂时的公共前缀,往后遍历,逐渐得到所有字符串的公共前缀。

public static String longestCommonPrefix00(String[] strs){
    if(strs==null||strs.length==0) return "";//传进空数组

    //将第一个字符串作为暂时作为公共前缀
    String prefix = strs[0];

    for (int i = 1; i < strs.length ; i++) {
        while(strs[i].indexOf(prefix)!=0){//不等于0说明第一个字符串并不是该字符串的前缀,则向前推移
            //prefix.substring(0,prefix.length()-1)  除去该字符串的最后一个字符
            prefix = prefix.substring(0,prefix.length()-1);
            //取到第一个字符,还是没有公共前缀,返回“”
            if(prefix.isEmpty()) return "";
        }
    }
    return prefix;
}

复杂度分析

  • 时间复杂度:O(S),S 是所有字符串中字符数量的总和。

    最坏的情况下,n 个字符串都是相同的。算法会将 S1 与其他字符串都做一次比较。这样就会进行 S 次字符比较,其中 S 是输入数据中所有字符数量。

  • 空间复杂度:O(1),我们只需要使用常数级别的额外空间。

垂直扫描

解题思路
从前往后枚举字符串的每一列,先比较每个字符串相同列上的字符(即不同字符串相同下标的字符)然后再进行对下一列的比较。

public static String longestCommonPrefix01(String[] strs){
    if(strs==null||strs.length==0) return "";
    //该for循环表示从前往后遍历比较某一个字符串每个位上的字符
    for(int i = 0;i<strs[0].length();i++){
        char c = strs[0].charAt(i);
        //该for循环表示从第二个字符串开始,从前往后遍历传入数组中的每个字符串
        for(int j = 1;j<strs.length;j++){
            // 两个判断条件:i
            // 1.i==strs[j].length()
            // i表示第一个字符串的位数,如果i和后面字符串的长度相等,就不对(位数是从0开始计数的,长度从1开始的)
            // 2.strs[j].charAt(i)!=c
            // 后面的字符串在相同位数时,字符不一致,即不对。
            // 两者情况任一满足一个,就返回第一个字符串0~i-1位数的字符串

            if(i==strs[j].length()||strs[j].charAt(i)!=c){
                //public String substring(int beginIndex,int endIndex)
                //返回一个字符串,该字符串是此字符串的子字符串。
                // 子串开始于指定beginIndex并延伸到字符索引endIndex - 1 。
                return strs[0].substring(0,i);

            }
        }
    }
    return strs[0];
}

复杂度分析

  • 时间复杂度:o(s),s是所有字符串的总字符数。
    最坏的情况,输入n个长度为m的相字符串,s=nm。最坏的情况和第一种一样,但是最好的情况下,只需要进行[字符串个数][最短字符串的长度]次数的比较。
  • 空间复杂度:o(1),只需要常数级别的额外空间。

分治解法

解题思路:即将所有字符串拆分,每一部分的公共前缀的公共前缀,必然是所有字符串的公共前缀。

    public static String longestCommonPrefix02(String[] strs){
        if(strs == null||strs.length==0) return "";
        return longestCommonPrefix(strs,strs.length-1);
    }
    private static String longestCommonPrefix(String[] strs,int left,int right){
        //跳出递归的情况
        if(left==right){
            return strs[left];
        }
        else{
            //分治
            int mid = (left+right)/2;
            String lcpLeft = longestCommonPrefix(strs,left,mid);
            String lcpRight = longestCommonPrefix(strs,mid+1,right);
            return CommonPrefix(lcpLeft,lcpRight);
        }
    }
    //普通比较两个字符串的最长前缀的方法,按字符比较,最多是到其中较短的字符串的长度位数位置
    private static String CommonPrefix(String left,String right){
        //min变量存储较短字符串的长度
        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);
        }
        //跳出for循环,说明较短的字符串就是公共前缀
        return left.substring(0,min);
    }

复杂度分析

  • 时间复杂度:o(s),s是所有字符串的总字符数。
    最坏的情况,输入n个长度为m的相字符串。但是最好的情况下,只需要进行[字符串个数]*[最短字符串的长度]次数的比较。
  • 空间复杂度:o(mlog(n))
    内存开支主要是递归过程中使用栈空间所消耗。log(n)次递归,每次需要m的空间存储返回结果。

二分查找

解题思路:最短字符串的长度就是公共前缀的最大可能长度。将字符串一分为二,每次经过判断,丢弃一部分,最终找到公共前缀。

public static String longestCommonPrefix03(String[] strs){
    if(strs==null||strs.length==0) return "";
    int minLen = Integer.MAX_VALUE;
    //最长公共前缀的最大可能长度就是最短的字符串长度
    //找出字符串数组中最短字符串的长度  minLen
    for(String str:strs)
        minLen = Math.min(minLen,str.length());
    int low = 1;
    int high = minLen;
    while(low<=high){
        //将查找空间一分为二
        int mid =(low+high)/2;
        //如果第一个字符串前面一半字符是所有串的公共前缀,那么就可以丢弃前一半查找空间
        if(isCommonPrefix(strs,mid))
            low = mid +1;
        //如果不是的话,丢弃后一半
        else
            high = mid -1;
    }
    //找到最长前缀的最后位置,并返回
    return strs[0].substring(0,(low+high)/2);
}
//判断传入数组的第一个字符串的前len位是不是后面的前缀,是返回true, 不是返回false
private static 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)),s是所有字符串的总字符数。
    最坏的情况,输入n个长度为m的相字符串。一共进行log(n)次迭代,每次都会进行s次比较。
  • 空间复杂度:o(1),只需要常数级别的额外空间。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


输出自然数 1 到 n所有不重复的排列,即 n的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
编写一个能够输出“`Hello,World!`”的程序,这个程序常常作为一个初学者接触一门新的编程语言所写的第一个程序,也经常用来测试开发、编译环境是否能够正常工作。&#xA;&#xA;提示:“`Hello,Worl
题目相关 【题目描述】 求10000以内n的阶乘。 【输入】 只有一行输入,整数n(0≤n≤10000)。 【输出】 一行,即n!的值。 【输入样例】 4 【输出样例】 24 分析 首先n的阶乘是从1
题目相关 原题链接:P5461 赦免战俘 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目背景 借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了! 题目描述 现有 $2n
水仙花数 题目描述 输出所有的&amp;quot;水仙花数&amp;quot;.所谓&amp;quot;水仙花数&amp;quot;是指这样的一个三位数:其各位数字的立方和等于该数本身。例如:371是
题目描述 奖学金 某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文
已知正整数k满足2≤k≤9,现给出长度最大为30位的十进制非负整数c,求所有能整除c的k。
题目相关 题目描述 我们要求找出具有下列性质数的个数(包含输入的正整数 n)。 先输入一个正整数 n(n ≤1000),然后对此正整数按照如下方法进行处理: 不作任何处理; 在它的左边加上一个正整数,
题目相关 题目描述 排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且 r ≤n),我们可以简单地将n个元素理解为自然数1,2,…,n从中任取r个数。 现要求你输出所有组合。
题目相关 题目描述 把 m个同样的苹果放在 n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法。(5,1,1 和 1,1,5 是同一种方法) 输入格式 第一行是测试数据的数目 t,以下每行
题目相关 【题目描述】 求两个不超过200位的非负整数的和。 【输入】 有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。 【输出】 一行,即相加后的结果。结果里不能有多余的前导0,即如
请你编一程序实现两种不同进制之间的数据转换。
题目相关 【题目描述】 求两个大的正整数相减的差。 【输入】 共2行,第1行是被减数a,第2行是减数b(a &amp;gt; b)。每个大整数不超过200位,不会有多余的前导零。 【输出】 一行,即所
题目描述 一个数如果恰好等于不包含它本身所有因子之和,这个数就称为&amp;quot;完数&amp;quot;。 例如,6的因子为1、2、3,而6=1ʲʳ,因此6是&amp;quot;完数&amp
题目相关 【题目描述】 任意给定一个正整数N(N≤100),计算2的n次方的值。 【输入】 输入一个正整数N。 【输出】 输出2的N次方的值。 【输入样例】 5 【输出样例】 32 分析 本题考察的是
题目相关 【题目描述】 输入三个整数,整数之间由一个空格分隔,整数是32位有符号整数。把第二个输入的整数输出。 【输入】 只有一行,共三个整数,整数之间由一个空格分隔。整数是32位有符号整数。 【输出
79. 单词搜索 给定一个二维网格和一个单词,找出该单词是否存在于网格中。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母
[toc] 707.设计双向链表 链表简介 链表(LinkedList) 是一种线性表,但不是顺序表,因为它是通过节点直接的相互引用相互联系起来的。 由于不必按顺序存储, 链表在插入和删除的时候可以达
题目描述 784. 字母大小写全排列 给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。 示例: 输入:S = &amp;quot;a1
[toc] Leetcode动态规划【简单题】 动态规划 (Dynamic programming,简称DP),是一种把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划相较于递归,拥有更