题目描述(中等难度)

给一个数组,把连续的数字写成 x->y 的形式。

解法一

直接按照题目意思遍历一遍就可以。判断是否连续只需要判断当前数字和后一个数字是否相差 1 即可。发生不连续的时候,将当前范围保存起来。

public List<String> summaryRanges(int[] nums) {
    int n = nums.length;
    if (n == 0) {
        return new ArrayList<>();
    }
    int start = nums[0];
    int end = nums[0];
    List<String> res = new ArrayList<>();
    for (int i = 0; i < n - 1; i++) {
        if (nums[i] + 1 != nums[i + 1]) {
            //发生了不连续,当前数字是范围的结束
            end = nums[i];
            if (start != end) {
                res.add(start + "->" + end);
            } else {
                res.add(start + "");
            }
            //下一个数字作为范围的开头
            start = nums[i + 1];
        }
    }
    //上边循环只遍历到了 n - 2, 所以最后一个数字单独考虑一下
    end = nums[n - 1];
    if (start != end) {
        res.add(start + "->" + end);
    } else {
        res.add(start + "");
    }
    return res;
}

解法二

上边解法不管最好还是最坏,时间复杂度都是 O(n),分享 这里) 的一个解法,可以对某些情况进行优化。

我们可以一半一半的考虑,比如 1 2 3 4 5 7。先考虑左半部 1 2 3 是否连续,只需要判断下标之差和数字之差是否相等。2 - 0 == 3 - 1,所以左半部分是连续的数字,得到一个范围 1 -> 3,而不需要向解法一那样一个一个数字的遍历。

这里带来一个问题,判断右半部分的时候,我们知道 4 -> 5,但是它应该和左半部连接起来变成 1 -> 5。这里的话,我们需要定义一个 Range 类,当加入新的范围的时候,判断一下两个范围是否相连即可。

class Range {
    int start;
    int end;

    Range(int s, int e) {
        start = s;
        end = e;
    }
}

public List<String> summaryRanges(int[] nums) {

    List<String> resStr = new ArrayList<>();

    if (nums.length == 0) {
        return resStr;
    }

    List<Range> res = new ArrayList<>();
    helper(nums, 0, nums.length - 1, res);

    for (Range r : res) {
        if (r.start == r.end) {
            resStr.add(Integer.toString(r.start));
        } else {
            resStr.add(r.start + "->" + r.end);
        }
    }

    return resStr;
}

private void helper(int[] nums, int i, int j, List<Range> res) {
    if (i == j || nums[j] - nums[i] == j - i) {
        add2res(nums[i], nums[j], res);
        return;
    }

    int m = (i + j) / 2;
    //一半一半的考虑
    helper(nums, i, m, res);
    helper(nums, m + 1, j, res);
}

private void add2res(int a, int b, List<Range> res) {
    //判断新加入的范围和之前最后一个范围是否相连
    if (res.isEmpty() || res.get(res.size() - 1).end + 1 != a) {
        res.add(new Range(a, b));
    } else {
        res.get(res.size() - 1).end = b;
    }
}

虽然最坏的时间复杂度依旧是 O(n)(比如所有的数字全部不相连),但对于某些情况带来了很大的提升。

解法一就是根据题意写出的一个解法,解法二的话通过二分的方式对解法带来了一定程度上的优化。

results matching ""

    No results matching ""