目录
题目
题目内容:
在一根很高的竹子上生活着一群螳螂,每只螳螂都有一段自己的势力范围,不同螳螂在竹子上的领地有可能重叠,当发现自己的领地内出现其它螳螂时就会战斗,失败一方领地会被胜利一方螳螂占领。
输入描述:
输入二维数组 originalLand,originalLand[i]=[x,y],表示第 i 只螳螂的领地在离地高度 [x,y] 之间的主干上 (x<y), 1 <= 数量 <= 50,0 <= x < y <= 150。
输出描述:
输出请返回领地斗争结束后螳螂们的领地信息。返回的领地信息数组中,按照领地坐标升序返回。
样例 1
输入:
[[1,5],[4,6],[8,15]]
输出:
[[1,6],[8,15]]
样例 2
输入:
[[3,7],[9,13]]
输出:
[[3,7],[9,13]]
样例 3
输入:
[[1,4],[4,5]]
输出:
[[1,5]]
思路
整体思路:按左端点排序后线性合并重叠或接触的闭区间。
第一步:按左端点、右端点升序排序。
第二步:当前左端点严格大于结果末段右端点时新增区间。
第三步:否则扩展末段右端点。
边界处理:端点相等必须合并;被完全包含的区间不会缩小合并段。
复杂度分析:时间 O(N log N),空间 O(N)。
Code
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class Main {
public static void main(String[] args) throws Exception {
Matcher matcher =
Pattern.compile("\\d+").matcher(new String(System.in.readAllBytes()));
List<int[]> lands = new ArrayList<>();
// 每两个整数按原顺序还原为闭区间。
// lands 中每个元素都保存一只螳螂的左、右边界,两个端点都属于它的领地。
while (matcher.find()) {
int left = Integer.parseInt(matcher.group());
matcher.find();
lands.add(new int[] {left, Integer.parseInt(matcher.group())});
}
// 左端点升序后只需比较结果中的最后一段。
// 排序后,尚未处理区间的左端点不会变小,因此只需和已合并结果的最后一段比较。
lands.sort((a, b)
-> a[0] != b[0] ? Integer.compare(a[0], b[0])
: Integer.compare(a[1], b[1]));
List<int[]> merged = new ArrayList<>();
merged.add(lands.get(0).clone());
for (int i = 1; i < lands.size(); i++) {
int[] current = lands.get(i), last = merged.get(merged.size() - 1);
if (current[0] > last[1]) {
// 端点相等也会冲突,只有严格大于才新增区间。
// 因为领地是闭区间,当前左端点等于已合并末段的右端点时共享同一位置,也必须视为冲突。
merged.add(current.clone());
} else {
// 相交时扩展最右边界,维持末段的区间并集不变量。
// 发生冲突后左边界仍是较早区间的起点,右边界取两段终点的较大值即可覆盖并集。
last[1] = Math.max(last[1], current[1]);
}
}
// 合并扫描不会打乱左端点顺序,所以无需再次排序,只按当前顺序拼接二维数组。
StringJoiner output = new StringJoiner(",", "[", "]");
for (int[] item : merged)
output.add("[" + item[0] + "," + item[1] + "]");
System.out.println(output);
}
}
Go
package main
import (
"fmt"
"io"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
type interval struct { left, right int }
func main() {
data, _ := io.ReadAll(os.Stdin)
tokens := regexp.MustCompile(`\d+`).FindAllString(string(data), -1)
// 每两个整数按顺序还原为闭区间。
// lands 中每个元素都保存一只螳螂的左、右边界,两个端点都属于它的领地。
lands := make([]interval, 0, len(tokens)/2)
for i := 0; i+1 < len(tokens); i += 2 {
left, _ := strconv.Atoi(tokens[i]); right, _ := strconv.Atoi(tokens[i+1])
lands = append(lands, interval{left, right})
}
// 左端点升序后,与当前结果末段冲突的区间连续出现。
// 排序后,尚未处理区间的左端点不会变小,因此只需和已合并结果的最后一段比较。
sort.Slice(lands, func(i, j int) bool {
if lands[i].left != lands[j].left { return lands[i].left < lands[j].left }
return lands[i].right < lands[j].right
})
merged := []interval{lands[0]}
for _, current := range lands[1:] {
last := &merged[len(merged)-1]
if current.left > last.right {
// 严格分离才新增段,端点接触也需要合并。
// 因为领地是闭区间,当前左端点等于已合并末段的右端点时共享同一位置,也必须视为冲突。
merged = append(merged, current)
} else if current.right > last.right {
// 相交时扩展并集右边界。
// 发生冲突后左边界仍是较早区间的起点,右边界取两段终点的较大值即可覆盖并集。
last.right = current.right
}
}
parts := make([]string, len(merged))
for i, item := range merged { parts[i] = fmt.Sprintf("[%d,%d]", item.left, item.right) }
// Join 生成升序、无空格二维数组。
// 合并扫描不会打乱左端点顺序,所以无需再次排序,只按当前顺序拼接二维数组。
fmt.Printf("[%s]\n", strings.Join(parts, ","))
}
C
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int left;
int right;
} Interval;
int compare_interval(const void *a, const void *b) {
const Interval *x = a, *y = b;
if (x->left != y->left)
return x->left - y->left;
return x->right - y->right;
}
int main(void) {
Interval lands[50];
int size = 0, left;
// 跳过括号和逗号,每两个整数还原为闭区间。
// lands 中每个元素都保存一只螳螂的左、右边界,两个端点都属于它的领地。
while (scanf("%*[^0-9]") != EOF || 1) {
if (scanf("%d", &left) != 1)
break;
scanf("%*[^0-9]");
scanf("%d", &lands[size].right);
lands[size++].left = left;
}
// 左端点排序后只需与结果末段比较。
// 排序后,尚未处理区间的左端点不会变小,因此只需和已合并结果的最后一段比较。
qsort(lands, (size_t)size, sizeof(Interval), compare_interval);
Interval merged[50];
int count = 1;
merged[0] = lands[0];
for (int i = 1; i < size; i++) {
if (lands[i].left > merged[count - 1].right) {
// 只有严格分离才新增区间,端点接触同样冲突。
// 因为领地是闭区间,当前左端点等于已合并末段的右端点时共享同一位置,也必须视为冲突。
merged[count++] = lands[i];
} else if (lands[i].right > merged[count - 1].right) {
// 相交区间向右延伸时更新并集右边界。
// 发生冲突后左边界仍是较早区间的起点,右边界取两段终点的较大值即可覆盖并集。
merged[count - 1].right = lands[i].right;
}
}
// 合并结果按坐标升序并使用紧凑格式。
// 合并扫描不会打乱左端点顺序,所以无需再次排序,只按当前顺序拼接二维数组。
printf("[");
for (int i = 0; i < count; i++)
printf(i ? ",[%d,%d]" : "[%d,%d]", merged[i].left, merged[i].right);
printf("]\n");
return 0;
}
【华为od机试真题Python+JS+Java+Go合集】【超值优惠】:Py/JS/Java/Go合集
【华为od机试真题Python】:Python真题题库
【华为od机试真题JavaScript】:JavaScript真题题库
【华为od机试真题Java&Go】:Java&Go真题题库
【华为od机试真题C++】:C++真题题库
【华为od机试真题C语言】:C语言真题题库
【华为od面试手撕代码题库】:面试手撕代码题库
【华为od机试面试交流群】【文章底部有二维码链接,可扫码加交流群】

华为OD机试:二本院校有机会吗? 有机会,但不大,大神除外!机考分数越高越好,所以需要提前刷题。机考通过后,如果没有收到面试邀请,也不要着急,非目标院校面试邀请发的时间比较晚。非目标院校今年有点难,机试至少要考到350分,所以需要疯狂刷题,华为OD机考是有题库的,最好在考前完所有题库题目。华为OD机试:跨专业可以参加华为OD可以,但是如果你的本科院校比较差,上岸概率不大。华为OD机试:华为OD简历被锁定机试通过,性格测试也通过,但是没人联系面试,发现简历被锁定。此时需要主动去联系HR。让他帮助你查询原因。

679




被折叠的 条评论
为什么被折叠?



