(A卷,200分)- 区间交叠问题(Java & JS & Python)

题目描述

给定坐标轴上的一组线段,线段的起点和终点均为整数并且长度不小于1,请你从中找到最少数量的线段,这些线段可以覆盖柱所有线段。

输入描述

第一行输入为所有线段的数量,不超过10000,后面每行表示一条线段,格式为"x,y",x和y分别表示起点和终点,取值范围是[-10^5,10^5]。

输出描述

最少线段数量,为正整数

用例

输入

3
1,4
2,5
3,6

输出 2
说明

题目解析

用例1图示如下

可以发现,只要选择[]1,4[和[3,6]就可以覆盖住所有给定线段。

我的解题思路如下:

首先,将所有区间ranges按照开始位置升序。

然后,创建一个辅助的栈stack,初始时将排序后的第一个区间压入栈中。

然后,遍历出1~ranges.length范围内的每一个区间ranges[i],将遍历到ranges[i]和stack栈顶区间对比:

  • 如果stack栈顶区间可以包含ranges[i]区间,则range[i]不压入栈顶
  • 如果stack栈顶区间被ranges[i]区间包含,则弹出stack栈顶元素,继续比较ranges[i]和stack新的栈顶元素
  • 如果stack栈顶区间和ranges[i]无法互相包含,只有部分交集,则将ranges[i]区间去除交集部分后,剩余部分区间压入stack
  • 如果stack栈顶区间和ranges[i]区间没有交集,那么直接将ranges[i]压入栈顶

这样的话,最终stack中有多少个区间,就代表至少需要多少个区间才能覆盖所有线段。

比如,用例1的运行流程如下:

2,5 和 1,4 存在重叠区间,我们只保留2,5区间的非重叠部分4,5

比较4,5区间和3,6区间,发现3,6完全涵盖2,5,因此2,5区间不再需要,可以从stack中弹栈删掉,即原始的2,5区间被删除了。

继续比较1,4和3,6区间,发现无法互相涵盖,因此都需要保留,但是3,6有部分区间和1,4重叠,因此只保留3,6不重叠部分4,6。

最终只需要两个区间,对应1,4、3,6,即可涵盖所有线段 

自测用例:

8
0,4
1,2
1,4
3,7
6,8
10,12
11,13
12,14

 输出5,即至少需要上面标红的五个区间才能覆盖所有线段。


2023.01.27

根据网友指正,上面逻辑缺失一个场景,比如:

3

1,10

5,12

8,11

按找前面逻辑,首先对所有区间按开始位置升序,然后将1,10入栈

然后尝试将5,12入栈,发现和栈顶区间有交集,因此去除交集部分后,5,12变为10,12,入栈

 然后尝试将8,11入栈,但是此时出现一个尴尬的情况,那就是栈顶区间10,12不能完全包含8,11,因此8,11区间还需要和栈顶前一个区间1,10继续比较,这就背离了我们一开始将所有区间按开始位置升序的初衷了。。。

而导致这个问题的根本原因是,栈顶区间10,12是被裁剪过的,因此导致它的起始位置落后了,即可能无法包含住升序后下一个区间的起始位置了,但是转念一想,先入栈的区间的起始位置肯定是要小于等于后入栈的区间的,因此栈顶区间被裁剪,说明栈顶区间和前一个区间必然是严密结合的,因此8,11的起始位置超出了栈顶区间,其实还是会被栈顶前一个区间包含进去。因此这里8,11不入栈。 

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
let n;
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 1) {
    n = lines[0] - 0;
  }

  if (n && lines.length === n + 1) {
    lines.shift();
    const ranges = lines.map((line) => line.split(",").map(Number));
    console.log(getResult(ranges, n));

    lines.length = 0;
  }
});

function getResult(ranges, n) {
  ranges.sort((a, b) => a[0] - b[0]);

  const stack = [ranges[0]];

  for (let i = 1; i < ranges.length; i++) {
    const range = ranges[i];

    while (true) {
      if (stack.length == 0) {
        stack.push(range);
        break;
      }

      const [s0, e0] = stack.at(-1);
      const [s1, e1] = range;

      if (s1 <= s0) {
        if (e1 <= s0) {
          break;
        } else if (e1 < e0) {
          break;
        } else {
          stack.pop();
        }
      } else if (s1 < e0) {
        if (e1 <= e0) {
          break;
        } else {
          stack.push([e0, e1]);
          break;
        }
      } else {
        stack.push(range);
        break;
      }
    }
  }

  //console.log(stack);

  return stack.length;
}

Java算法源码

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    int n = Integer.parseInt(sc.nextLine());

    Integer[][] ranges = new Integer[n][];
    for (int i = 0; i < n; i++) {
      ranges[i] =
          Arrays.stream(sc.nextLine().split(",")).map(Integer::parseInt).toArray(Integer[]::new);
    }

    System.out.println(getResult(ranges));
  }

  public static int getResult(Integer[][] ranges) {
    Arrays.sort(ranges, (a, b) -> a[0] - b[0]);

    LinkedList<Integer[]> stack = new LinkedList<>();
    stack.add(ranges[0]);

    for (int i = 1; i < ranges.length; i++) {
      Integer[] range = ranges[i];

      while (true) {
        if (stack.size() == 0) {
          stack.add(range);
          break;
        }

        Integer[] top = stack.getLast();
        int s0 = top[0];
        int e0 = top[1];

        int s1 = range[0];
        int e1 = range[1];

        if (s1 <= s0) {
          if (e1 <= s0) {
            break;
          } else if (e1 < e0) {
            break;
          } else {
            stack.removeLast();
          }
        } else if (s1 < e0) {
          if (e1 <= e0) {
            break;
          } else {
            stack.add(new Integer[] {e0, e1});
            break;
          }
        } else {
          stack.add(range);
          break;
        }
      }
    }

    return stack.size();
  }
}

Python算法源码

# 输入获取
n = int(input())
rans = [list(map(int, input().split(","))) for i in range(n)]


# 算法入口
def getResult(rans, n):
    rans.sort(key=lambda x: x[0])
    stack = [rans[0]]

    for i in range(1, n):
        ran = rans[i]

        while True:
            if len(stack) == 0:
                stack.append(ran)
                break

            s0, e0 = stack[-1]
            s1, e1 = ran

            if s1 <= s0:
                if e1 <= s0:
                    break
                elif e1 < e0:
                    break
                else:
                    stack.pop()
            elif s1 < e0:
                if e1 <= e0:
                    break
                else:
                    stack.append([e0, e1])
                    break
            else:
                stack.append(ran)
                break

    return len(stack)


# 算法调用
print(getResult(rans, n))

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?