题目描述(中等难度)

228. Summary Ranges - 图1

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

解法一

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

  1. public List<String> summaryRanges(int[] nums) {
  2. int n = nums.length;
  3. if (n == 0) {
  4. return new ArrayList<>();
  5. }
  6. int start = nums[0];
  7. int end = nums[0];
  8. List<String> res = new ArrayList<>();
  9. for (int i = 0; i < n - 1; i++) {
  10. if (nums[i] + 1 != nums[i + 1]) {
  11. //发生了不连续,当前数字是范围的结束
  12. end = nums[i];
  13. if (start != end) {
  14. res.add(start + "->" + end);
  15. } else {
  16. res.add(start + "");
  17. }
  18. //下一个数字作为范围的开头
  19. start = nums[i + 1];
  20. }
  21. }
  22. //上边循环只遍历到了 n - 2, 所以最后一个数字单独考虑一下
  23. end = nums[n - 1];
  24. if (start != end) {
  25. res.add(start + "->" + end);
  26. } else {
  27. res.add(start + "");
  28. }
  29. return res;
  30. }

解法二

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

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

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

  1. class Range {
  2. int start;
  3. int end;
  4. Range(int s, int e) {
  5. start = s;
  6. end = e;
  7. }
  8. }
  9. public List<String> summaryRanges(int[] nums) {
  10. List<String> resStr = new ArrayList<>();
  11. if (nums.length == 0) {
  12. return resStr;
  13. }
  14. List<Range> res = new ArrayList<>();
  15. helper(nums, 0, nums.length - 1, res);
  16. for (Range r : res) {
  17. if (r.start == r.end) {
  18. resStr.add(Integer.toString(r.start));
  19. } else {
  20. resStr.add(r.start + "->" + r.end);
  21. }
  22. }
  23. return resStr;
  24. }
  25. private void helper(int[] nums, int i, int j, List<Range> res) {
  26. if (i == j || nums[j] - nums[i] == j - i) {
  27. add2res(nums[i], nums[j], res);
  28. return;
  29. }
  30. int m = (i + j) / 2;
  31. //一半一半的考虑
  32. helper(nums, i, m, res);
  33. helper(nums, m + 1, j, res);
  34. }
  35. private void add2res(int a, int b, List<Range> res) {
  36. //判断新加入的范围和之前最后一个范围是否相连
  37. if (res.isEmpty() || res.get(res.size() - 1).end + 1 != a) {
  38. res.add(new Range(a, b));
  39. } else {
  40. res.get(res.size() - 1).end = b;
  41. }
  42. }

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

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

windliang wechat

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情