最长公共前缀 [分治 & 抽象二分练习]

218 阅读1分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第15篇文章,最长公共前缀 [分治 & 抽象二分练习] - 掘金 (juejin.cn)

前言

对于一个问题,采用一题多解,才能深刻理解其考察的知识点,进行举一反三。最长公共前缀,可横向对比 / 竖向对比 / 最值对比 / 分治 / 二分方法来完成题解。

一、最长公共前缀

image.png

二、一题多解

1、纵向对比

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

2、横向对比

// idea6:横向扫描(暴力之一)
    public String longestCommonPrefix6(String[] strs) {
        String prefix = strs[0];

        for (String s : strs) prefix = compareStr(prefix, s);

        return prefix;
    }
    private String compareStr(String s1, String s2) {
        int idx = 0;
        while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;

        return s1.substring(0, idx);
    }

3、最值对比

public String longestCommonPrefix3(String[] strs) {
        String min = strs[0], max = strs[0];

        for (String str : strs) {
            // bug1:字符串的compare和integer的不一样,并非-1 / 0 / 1,而是长度相减作为返回值。
            if (min.compareTo(str) > 0) min = str;
            if (max.compareTo(str) < 0) max = str;
        }

        return compareStr(min, max);
    }
    private String compareStr(String s1, String s2) {
        int idx = 0;
        while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;

        return s1.substring(0, idx);
    }

4、分治

private String partition(String[] strs, int left, int right) {
        if (left == right) return strs[left];

        int mid = left + (right - left >> 1);
        String s1 = partition(strs, left, mid);
        String s2 = partition(strs, mid + 1, right);

        return compareStr(s1, s2);
    }
    private String compareStr(String s1, String s2) {
        int idx = 0;
        while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;

        return s1.substring(0, idx);
    }

5、二分

public String longestCommonPrefix5(String[] strs) {
        String s = strs[0];
        int low = 0, high = s.length();

        while (low < high) {
            int mid = low + (high - low + 1 >> 1);// 为了low不越界,这里必须+1防止死循环。
            String midStr = s.substring(0, mid);

            if (isMatchAll(strs, midStr)) low = mid;
            else high = mid - 1;
        }
        return s.substring(0, low);
    }

    private boolean isMatchAll(String[] strs, String str) {
        for (String s : strs) {
            if (s.length() < str.length() || !str.equals(s.substring(0, str.length()))) return false;
        }
        return true;
    }

总结

1)最长公共前缀,可横向对比 / 竖向对比 / 最值对比 / 分治 / 二分方法来完成题解。对于分治来讲,可多线程操作加快速度;对于二分,考察对抽象二分的理解,将二分规则进行抽象。

参考文献

[1] LeetCode 最长公共前缀

[2] LeetCode 最长公共前缀 官方题解