华为OD机试新系统真题【统计不重叠区间的个数】

统计不重叠区间的个数(C/C++/Py/Java/Js/Go)题解

华为OD机试新系统真题 华为OD上机考试新系统真题 6月28号 100分题型

华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解

题目内容

给定一个以二维数组 intervals \text{intervals} intervals 表示若干个区间的集合,其中单个区间为 intervals i = starti , endi \text{intervals}i = \\text{starti}, \\text{endi} intervalsi=starti,endi( starti \text{starti} starti 和 endi \text{endi} endi 都是整数),这些区间之间可能存在重叠,请统计跟其他任何区间都不重叠的区间数量。

输入描述

一个二维数组 intervals \text{intervals} intervals,每一行输入对应 intervalsi,。 \text{intervalsi},。 intervalsi,。 intervals i \text{intervals}i intervalsi 表示第 i i i 个区间, intervals i 0 \text{intervals}i0 intervalsi0 表示第 i i i 个区间的 starti \text{starti} starti, intervals i 1 \text{intervals}i1 intervalsi1 表示第 i i i 个区间的 endi \text{endi} endi。

输出描述

这个区间集合中跟其他区间都不重叠的区间数量。

补充说明:

  1. 1 ≤ intervals.length ≤ 10000 1 \le \text{intervals.length} \le 10000 1≤intervals.length≤10000
  2. intervals i . l e n g t h = = 2 \text{intervals}i.length == 2 intervalsi.length==2
  3. 0 ≤ starti ≤ endi ≤ 10000 0 \le \text{starti} \le \text{endi} \le 10000 0≤starti≤endi≤10000

样例1

输入

复制代码
8 10
1 4
2 6
15 18

输出

复制代码
2

说明

区间 8 , 10 8,10 8,10 15 , 18 15,18 15,18 跟其他区间都不重合

样例2

输入

复制代码
2 4
4 6

输出

复制代码
0

说明

2 , 4 2,4 2,4 4 , 6 4,6 4,6 这 2 2 2 个区间重叠,不存在跟其他区间都不重叠的区间,故返回 0 0 0

题解

思路:逻辑分析

  1. 首先对输入区间进行按照按左端点升序排序,左端点相同按右端点升序排序
  2. 接下来在考虑发生冲突的情况,intervals[i]发生重叠的区间情况为
    • 与左侧区间发生重叠情况为,[0..i-1]的最大区间end大于等于intervals[i].start
    • 与右侧区间发生重叠情况为,[i+1..n-1]的最小区间start小于等于intervals[i].end
  3. 按照2的分析可以预处理每个位置前缀最大end和后缀最小start,使用preMaxsufMin保存。
  4. 接下来进行从前往后遍历,如果preMax[i-1] < intervals[i].start && sufMin[i+1] > intervals[i].end则结果+1.

C++

cpp 复制代码
#include<bits/stdc++.h>
#include <vector>
using namespace std;

// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<int> split(const string& str, const string& delimiter) {
    vector<int> result;
    size_t start = 0;
    size_t end = str.find(delimiter);
    while (end != string::npos) {
        result.push_back(stoi(str.substr(start, end - start)));
        start = end + delimiter.length();
        end = str.find(delimiter, start);
    }
    // 添加最后一个部分
    result.push_back(stoi(str.substr(start)));
    return result;
}

int getIsolationInterval(vector<vector<int>>& intervals) {
    
    // 按左端点升序排序,左端点相同按右端点升序排序
    sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
        if (a[0] != b[0]) {
            return a[0] < b[0];
        }
        return a[1] < b[1];
    });
    int n = intervals.size();
    // preMax[i]右端点能取的最大值
    vector<int> preMax(n);
    preMax[0] = intervals[0][1];;
    for (int i = 1; i < n; i++) {
        preMax[i] = max(preMax[i - 1], intervals[i][1]);
    }
    // sufMin[i]左端点能取的最小值
    vector<int> sufMin(n);
    sufMin[n - 1] = intervals[n - 1][0];

    int ans = 0;
    for (int i = 0; i < n; i++) {
        // 左侧是否冲突
        bool leftOverlap = false;
        // 右侧是否冲突
        bool rightOverlap = false;
        if (i > 0 && preMax[i-1] >= intervals[i][0]) {
            leftOverlap = true;
        }
        if (i + 1 < n && sufMin[i+1] <= intervals[i][1]) {
            rightOverlap = true;
        }
        if (!leftOverlap && !rightOverlap) {
            ans++;
        }
    }
    return ans;
}


int main() {
    vector<vector<int>> intervals;
    string input;
    while (getline(cin, input)) {
        if (input.empty()) {
            break;
        }
        intervals.push_back(split(input, " "));
    }

    cout << getIsolationInterval(intervals);
    return 0;
}

Java

java 复制代码
import java.util.*;

public class Main {

    public static int getIsolationInterval(List<int[]> intervals) {

        // 按左端点升序排序,左端点相同按右端点升序排序
        intervals.sort((a, b) -> {
            if (a[0] != b[0]) {
                return Integer.compare(a[0], b[0]);
            }
            return Integer.compare(a[1], b[1]);
        });

        int n = intervals.size();

        // preMax[i]右端点能取的最大值
        int[] preMax = new int[n];
        preMax[0] = intervals.get(0)[1];
        for (int i = 1; i < n; i++) {
            preMax[i] = Math.max(preMax[i - 1], intervals.get(i)[1]);
        }

        // sufMin[i]左端点能取的最小值
        int[] sufMin = new int[n];
        sufMin[n - 1] = intervals.get(n - 1)[0];
        for (int i = n - 2; i >= 0; i--) {
            sufMin[i] = Math.min(sufMin[i + 1], intervals.get(i)[0]);
        }

        int ans = 0;
        for (int i = 0; i < n; i++) {
            // 左侧是否冲突
            boolean leftOverlap = false;
            // 右侧是否冲突
            boolean rightOverlap = false;

            if (i > 0 && preMax[i - 1] >= intervals.get(i)[0]) {
                leftOverlap = true;
            }

            if (i + 1 < n && sufMin[i + 1] <= intervals.get(i)[1]) {
                rightOverlap = true;
            }

            if (!leftOverlap && !rightOverlap) {
                ans++;
            }
        }

        return ans;
    }

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

        List<int[]> intervals = new ArrayList<>();

        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            if (line.isEmpty()) {
                break;
            }
            String[] strs = line.split(" ");
            intervals.add(new int[]{
                    Integer.parseInt(strs[0]),
                    Integer.parseInt(strs[1])
            });
        }

        System.out.println(getIsolationInterval(intervals));
    }
}

Python

python 复制代码
def getIsolationInterval(intervals):
    # 按左端点升序排序,左端点相同按右端点升序排序
    intervals.sort(key=lambda x: (x[0], x[1]))

    n = len(intervals)

    # preMax[i]右端点能取的最大值
    preMax = [0] * n
    preMax[0] = intervals[0][1]
    for i in range(1, n):
        preMax[i] = max(preMax[i - 1], intervals[i][1])

    # sufMin[i]左端点能取的最小值
    sufMin = [0] * n
    sufMin[-1] = intervals[-1][0]
    for i in range(n - 2, -1, -1):
        sufMin[i] = min(sufMin[i + 1], intervals[i][0])

    ans = 0

    for i in range(n):
        # 左侧是否冲突
        leftOverlap = False
        # 右侧是否冲突
        rightOverlap = False

        if i > 0 and preMax[i - 1] >= intervals[i][0]:
            leftOverlap = True

        if i + 1 < n and sufMin[i + 1] <= intervals[i][1]:
            rightOverlap = True

        if not leftOverlap and not rightOverlap:
            ans += 1

    return ans


intervals = []

try:
    while True:
        line = input()
        if line == "":
            break
        intervals.append(list(map(int, line.split())))
except EOFError:
    pass

print(getIsolationInterval(intervals))

JavaScript

js 复制代码
const readline = require("readline");

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

const intervals = [];

rl.on("line", (line) => {
    if (line.trim() !== "") {
        intervals.push(line.split(" ").map(Number));
    }
});

rl.on("close", () => {
    console.log(getIsolationInterval(intervals).toString());
});

function getIsolationInterval(intervals) {

    // 按左端点升序排序,左端点相同按右端点升序排序
    intervals.sort((a, b) => {
        if (a[0] !== b[0]) {
            return a[0] - b[0];
        }
        return a[1] - b[1];
    });

    const n = intervals.length;

    // preMax[i]右端点能取的最大值
    const preMax = new Array(n);
    preMax[0] = intervals[0][1];
    for (let i = 1; i < n; i++) {
        preMax[i] = Math.max(preMax[i - 1], intervals[i][1]);
    }

    // sufMin[i]左端点能取的最小值
    const sufMin = new Array(n);
    sufMin[n - 1] = intervals[n - 1][0];
    for (let i = n - 2; i >= 0; i--) {
        sufMin[i] = Math.min(sufMin[i + 1], intervals[i][0]);
    }

    let ans = 0;

    for (let i = 0; i < n; i++) {
        // 左侧是否冲突
        let leftOverlap = false;
        // 右侧是否冲突
        let rightOverlap = false;

        if (i > 0 && preMax[i - 1] >= intervals[i][0]) {
            leftOverlap = true;
        }

        if (i + 1 < n && sufMin[i + 1] <= intervals[i][1]) {
            rightOverlap = true;
        }

        if (!leftOverlap && !rightOverlap) {
            ans++;
        }
    }

    return ans;
}

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func getIsolationInterval(intervals [][]int) int {

	// 按左端点升序排序,左端点相同按右端点升序排序
	sort.Slice(intervals, func(i, j int) bool {
		if intervals[i][0] != intervals[j][0] {
			return intervals[i][0] < intervals[j][0]
		}
		return intervals[i][1] < intervals[j][1]
	})

	n := len(intervals)

	// preMax[i]右端点能取的最大值
	preMax := make([]int, n)
	preMax[0] = intervals[0][1]
	for i := 1; i < n; i++ {
		if preMax[i-1] > intervals[i][1] {
			preMax[i] = preMax[i-1]
		} else {
			preMax[i] = intervals[i][1]
		}
	}

	// sufMin[i]左端点能取的最小值
	sufMin := make([]int, n)
	sufMin[n-1] = intervals[n-1][0]
	for i := n - 2; i >= 0; i-- {
		if sufMin[i+1] < intervals[i][0] {
			sufMin[i] = sufMin[i+1]
		} else {
			sufMin[i] = intervals[i][0]
		}
	}

	ans := 0

	for i := 0; i < n; i++ {
		// 左侧是否冲突
		leftOverlap := false
		// 右侧是否冲突
		rightOverlap := false

		if i > 0 && preMax[i-1] >= intervals[i][0] {
			leftOverlap = true
		}

		if i+1 < n && sufMin[i+1] <= intervals[i][1] {
			rightOverlap = true
		}

		if !leftOverlap && !rightOverlap {
			ans++
		}
	}

	return ans
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	var intervals [][]int

	for scanner.Scan() {
		var l, r int
		line := scanner.Text()
		if line == "" {
			break
		}
		fmt.Sscanf(line, "%d %d", &l, &r)
		intervals = append(intervals, []int{l, r})
	}

	fmt.Println(getIsolationInterval(intervals))
}

C语言

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    int *x = (int *)a;
    int *y = (int *)b;

    if (x[0] != y[0]) {
        return x[0] - y[0];
    }
    return x[1] - y[1];
}

int getIsolationInterval(int intervals[][2], int n) {

    // 按左端点升序排序,左端点相同按右端点升序排序
    qsort(intervals, n, sizeof(intervals[0]), cmp);

    // preMax[i]右端点能取的最大值
    int preMax[n];
    preMax[0] = intervals[0][1];
    for (int i = 1; i < n; i++) {
        preMax[i] = preMax[i - 1] > intervals[i][1] ? preMax[i - 1] : intervals[i][1];
    }

    // sufMin[i]左端点能取的最小值
    int sufMin[n];
    sufMin[n - 1] = intervals[n - 1][0];
    for (int i = n - 2; i >= 0; i--) {
        sufMin[i] = sufMin[i + 1] < intervals[i][0] ? sufMin[i + 1] : intervals[i][0];
    }

    int ans = 0;

    for (int i = 0; i < n; i++) {
        // 左侧是否冲突
        int leftOverlap = 0;
        // 右侧是否冲突
        int rightOverlap = 0;

        if (i > 0 && preMax[i - 1] >= intervals[i][0]) {
            leftOverlap = 1;
        }

        if (i + 1 < n && sufMin[i + 1] <= intervals[i][1]) {
            rightOverlap = 1;
        }

        if (!leftOverlap && !rightOverlap) {
            ans++;
        }
    }

    return ans;
}

int main() {
    int intervals[10000][2];
    int n = 0;

    // 每行输入一个区间:start end
    while (scanf("%d %d", &intervals[n][0], &intervals[n][1]) == 2) {
        n++;
    }

    printf("%d\n", getIsolationInterval(intervals, n));

    return 0;
}