【OD机试题解法笔记】区间交集

题目

给定一组闭区间,其中部分区间存在交集。
任意两个给定区间的交集,称为公共区间 (如 [1,2],[2,3] 的公共区间为 [2,2],[3,5],[3,6] 的公共区间为 [3,5])。
公共区间之间若存在交集,则需要合并 (如 [1,3],[3,5] 区间存在交集 [3,3],需合并为 [1,5])。
按升序排列输出合并后的区间列表。

输入描述

一组区间列表,
区间数为 N: 0<=N<=1000;
区间元素为 X: -10000<=X<=10000。

输出描述

升序排列的合并区间列表

备注

1、区间元素均为数字,不考虑字母、符号等异常输入。
2、单个区间认定为无公共区间。

用例

输入输出说明
4
0 3
1 3
3 5
3 6
1 5[0,3] 和 [1,3] 的公共区间为 [1,3],
[0,3] 和 [3,5] 的公共区间为 [3,3],
[0,3] 和 [3,6] 的公共区间为 [3,3],
[1,3] 和 [3,5] 的公共区间为 [3,3],
[1,3] 和 [3,6] 的公共区间为 [3,3],
[3,5] 和 [3,6] 的公共区间为 [3,5],
公共区间列表为 [[1,3],[3,3],[3,5]];
[[1,3],[3,3],[3,5]] 存在交集,须合并为 [1,5]。
4
0 3
1 4
4 7
5 8
1 3
4 4
5 7

思考

  1. 提取公共区间:首先找出所有两两区间的交集,作为公共区间。
  2. 合并重叠公共区间:将提取的公共区间按起点排序,然后合并重叠或相邻的区间。

算法过程

  1. 输入处理:读取区间列表,存储为二维数组。
  2. 计算公共区间:遍历每对区间,计算它们的交集。若交集存在(起点≤终点),则加入公共区间列表。
  3. 排序公共区间:按公共区间的起点升序排序。
  4. 合并区间:遍历排序后的公共区间,合并重叠或相邻的区间(当前区间起点≤前一区间终点时合并)。

参考代码

function solution() {
  const N = parseInt(readline());
  if (N <= 1) { // 单个区间或无区间,直接输出空
    console.log('');
    return;
  }

  const list = [];
  for (let i = 0; i < N; i++) {
    const [start, end] = readline().split(' ').map(Number);
    list.push({ start, end });
  }

  // 提取所有两两区间的公共区间
  const commonIntervals = [];
  for (let i = 0; i < N; i++) {
    const a = list[i];
    for (let j = i + 1; j < N; j++) {
      const b = list[j];
      const start = Math.max(a.start, b.start);
      const end = Math.min(a.end, b.end);
      if (start <= end) {
        commonIntervals.push({ start: start, end: end });
      }
    }
  }

  if (commonIntervals.length === 0) { // 无公共区间
    console.log('');
    return;
  }

  // 按起点排序公共区间
  commonIntervals.sort((x, y) => x.start - y.start);

  // 合并重叠区间
  const merged = [commonIntervals[0]];
  for (let i = 1; i < commonIntervals.length; i++) {
    const curr = commonIntervals[i];
    const last = merged[merged.length - 1];
    if (curr.start <= last.end) { // 合并条件:当前起点 ≤ 前一终点
      merged[merged.length - 1] = {
        start: last.start,
        end: Math.max(last.end, curr.end)
      };
    } else {
      merged.push(curr);
    }
  }

  // 输出结果
  const output = merged.map(interval => `${interval.start} ${interval.end}`).join('\n');
  console.log(output);
}

const cases = [
  `4
0 3
1 3
3 5
3 6`,
`4
0 3
1 4
4 7
5 8`
];


let caseIndex = 0;
let lineIndex = 0;

const readline = (function () {
  let lines = [];
  return function () {
    if (lineIndex === 0) {
      lines = cases[caseIndex]
        .trim()
        .split("\n")
        .map((line) => line.trim());
    }
    return lines[lineIndex++];
  };
})();

cases.forEach((_, i) => {
  caseIndex = i;
  lineIndex = 0;
  solution();
});

### 华为 OD 试题及解答 #### Java 题目解析 在华为 OD 考中,Java 是一种常见的编程语言。以下是一个关于二进制位操作的经典题目及其解决方案。 给定一个整数 `num`,计算其二进制表示中有多少个 `1` 的方法可以通过逐位检查实现[^2]。 以下是具体的代码示例: ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int num = in.nextInt(); // 输入数字 int count = 0; // 计数器初始化 for (int i = 0; i < 32; i++) { // 假设输入的是标准的 32 位整数 if ((num & 1) == 1) { // 如果当前最低位是 1,则增加计数 count++; } num = num >>> 1; // 将数字无符号右移一位 } System.out.println(count); // 输出最终的结果 } } ``` 此程序的核心在于利用按位与运算符 (`&`) 和无符号右移运算符 (`>>>`) 来逐步提取并统计二进制中的每一位是否为 `1`。 --- #### 字符串处理题目解析 另一个常见问题是字符串的操作,比如将字符串中的每个单词首字母大写化[^3]。下面是一段 Python 实现的例子: ```python while True: try: words = input().split() # 获取用户输入并分割成列表 result = [] for word in words: if len(word) > 0: # 确保单词长度大于零 capitalized_word = f"{word[0].upper()}{word[1:]}" result.append(capitalized_word) print(" ".join(result)) # 打印结果 except Exception as e: break # 捕获异常后退出循环 ``` 该脚本通过遍历每一个单词,并将其第一个字符转为大写字母来完成任务。 --- #### 准备建议 为了更好地应对华为 OD 试,可以采取如下策略: - **熟悉常用算法**:掌握基本的数据结构(数组、链表、堆栈等)以及经典算法(排序、查找等),这些知识点经常会在实际测试中被考察到。 - **多练习编码能力**:针对不同类型的题目进行专项训练,尤其是时间复杂度优化方面的技巧学习。 - **理解业务场景需求**:部分试题可能结合具体应用场景设计,因此除了技术层面外还需要考虑逻辑思维的应用。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值