【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试之【模拟/数学】2023C-多段线数据压缩【欧弟算法】全网注释最详细分类最全的华为OD真题题解

80 篇文章 5 订阅
19 篇文章 0 订阅

有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1336了解算法冲刺训练

题目描述与示例

题目描述

下图中,每个方块代表一个像素,每个像素用其行号和列号表示。

在这里插入图片描述

为简化处理,多段线的走向只能是水平、竖直、斜向45度。

上图中的多段线可以用下面的坐标串表示:(2,8),(3,7),(3,6),(3,5),(4,4),(5,3),(6,2),(7,3),(8,4),(7,5)

但可以发现,这种表示不是最简的,其实只需要存储6个蓝色的关键点即可,它们是线段的起点、拐点、终点,而剩下4个点是冗余的。

现在,请根据输入的包含有几余数据的多段线坐标列表,输出其最化的结果。

输入描述

形如2 8 3 7 3 6 3 5 4 4 5 3 6 2 7 3 8 4 7 5

1、所有数字以空格分隔,每两个数字一组,第一个数字是行号,第二个数字是列号;

2、行号和列号范围为[0,64),用例输入保证不会越界,考生不必检查;

3、输入数据至少包含两个坐标点。

输出描述

形如2 8 3 7 3 5 6 2 8 4 7 5

压缩后的最简化坐标列表,和输入数据的格式相同。

补充说明

输出的坐标相对顺序不能变化。

示例

输入

2 8 3 7 3 6 3 5 4 4 5 3 6 2 7 3 8 4 7 5

输出

2 8 3 7 3 5 6 2 8 4 7 5

说明

如上图所示,6个蓝色像素的坐标依次是(2,8)、(3,7)、(3,5)、(6,2)、(8,4)、(7,5)

将他们按顺序出即可。

解题思路

本题的核心在于如何判定三点共线。

已知三个点ABC坐标分别为(x1, y1)(x2, y2)(x3, y3),那么向量ABAC分别可以用(x2-x1, y2-y1)以及(x3-x1, y3-y1)来表示。

三点共线等价于这两个向量平行,即等价于(x2-x1)*(y3-y1) == (x3-x1)*(y2-y1)成立。

因此我们可以固定一个起始端点start_point来表示某一段线段的起始端点。start_point初始化为所有点中的第一个坐标。起始端点需要加入到答案列表ans中。

然后遍历所有点points,考虑临近的两个点points[i]poins[i-1]。若start_pointpoints[i]poins[i-1]

  • 位于同一条直线上,那么说明中间的点poins[i-1]是可以忽略的。即如下图所示的情况

在这里插入图片描述

  • 不位于同一条直线上,那么说明中间的点poins[i-1]是不可以忽略的,是一个拐点,需要加入到答案列表ans中。同时将start_point修改为poins[i-1],表示下一个线段的起始端点为poins[i-1]

在这里插入图片描述

注意遍历结束后,最后一个点(终点)还需要加入到答案列表ans中。总体的核心代码如下

start_point = points[0]
ans = [start_point]
for i in range(1, n):
    if check_same_line(start_point, points[i-1], points[i]):
        continue
    else:
        ans.append(points[i-1])
        start_point = points[i-1]
ans.append(points[-1])
print(" ".join(f"{p[0]} {p[1]}" for p in ans))

代码

Python

# 题目:【模拟】2023C-多段线数据压缩
# 分值:100
# 作者:许老师-闭着眼睛学数理化
# 算法:模拟
# 代码看不懂的地方,请直接在群上提问


# 检查是否三点共线的函数
# p1, p2, p3分别为二元组,表示一个点
def check_same_line(p1, p2, p3):
    x1, y1 = p1
    x2, y2 = p2
    x3, y3 = p3
    return (x2-x1)*(y3-y1) == (x3-x1)*(y2-y1)


# 输入一行数据,包含2*n个坐标
lst = list(map(int, input().split()))
# 将lst转化为n个点,储存在二维列表points中
points = [[lst[i], lst[i+1]] for i in range(0, len(lst), 2)]
# 获得点的个数n
n = len(points)
# 初始化起始端点
start_point = points[0]
# 初始化答案列表,包含起始端点
ans = [start_point]
for i in range(1, n):
    # 检查start_point、points[i-1]和points[i]是否三点共线
    # 若是,说明points[i-1]被忽略,则可以直接跳过
    if check_same_line(start_point, points[i-1], points[i]):
        continue
    # 否则,说明points[i-1]是一个拐点,加入ans中
    # 同时需要修改points[i-1]为新的起始端点start_point
    else:
        ans.append(points[i-1])
        start_point = points[i-1]

# 加入最后一个点的坐标,为终止点
ans.append(points[-1])
# 将ans中的所有二元组输出为1行
print(" ".join(f"{p[0]} {p[1]}" for p in ans))

Java

import java.util.*;

public class Main {
    // 检查是否三点共线的函数
    public static boolean checkSameLine(int[] p1, int[] p2, int[] p3) {
        int x1 = p1[0], y1 = p1[1];
        int x2 = p2[0], y2 = p2[1];
        int x3 = p3[0], y3 = p3[1];
        return (x2 - x1) * (y3 - y1) == (x3 - x1) * (y2 - y1);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] input = scanner.nextLine().split(" ");
        int n = input.length / 2; // 获取点的个数n
        int[][] points = new int[n][2]; // 初始化存储点的二维数组
        // 将输入转化为二维数组
        for (int i = 0; i < n; i++) {
            points[i][0] = Integer.parseInt(input[2 * i]);
            points[i][1] = Integer.parseInt(input[2 * i + 1]);
        }

        // 初始化起始端点
        int[] startPoint = points[0];
        List<int[]> ans = new ArrayList<>();
        ans.add(startPoint);

        for (int i = 1; i < n; i++) {
            // 检查startPoint、points[i-1]和points[i]是否三点共线
            // 若是,说明points[i-1]被忽略,则可以直接跳过
            if (checkSameLine(startPoint, points[i - 1], points[i])) {
                continue;
            }
            // 否则,说明points[i-1]是一个拐点,加入ans中
            // 同时需要修改points[i-1]为新的起始端点startPoint
            else {
                ans.add(points[i - 1]);
                startPoint = points[i - 1];
            }
        }
        // 加入最后一个点的坐标,为终止点
        ans.add(points[n - 1]);

        // 将ans中的所有二元组输出为1行
        for (int[] point : ans) {
            System.out.print(point[0] + " " + point[1] + " ");
        }
    }
}

C++

#include <iostream>
#include <vector>

using namespace std;

// 检查是否三点共线的函数
bool checkSameLine(const vector<int>& p1, const vector<int>& p2, const vector<int>& p3) {
    int x1 = p1[0], y1 = p1[1];
    int x2 = p2[0], y2 = p2[1];
    int x3 = p3[0], y3 = p3[1];
    return (x2 - x1) * (y3 - y1) == (x3 - x1) * (y2 - y1);
}

int main() {
    // 输入一行数据,包含2*n个坐标
    vector<int> points;
    int num;
    while (cin >> num) {
        points.push_back(num);
    }
    int n = points.size() / 2; // 获取点的个数n
    vector<vector<int>> ans; // 初始化存储点的二维数组
    ans.push_back({points[0], points[1]}); // 将起始端点加入结果中

    // 从第二个点开始遍历
    for (int i = 1; i < n; i++) {
        // 检查当前点与前一个点是否共线
        if (checkSameLine(ans.back(), {points[2 * (i - 1)], points[2 * (i - 1) + 1]}, {points[2 * i], points[2 * i + 1]})) {
            continue; // 如果共线,忽略当前点
        } else {
            ans.push_back({points[2 * (i - 1)], points[2 * (i - 1) + 1]}); // 否则将前一个点加入结果中
        }
    }
    // 加入最后一个点的坐标,为终止点
    ans.push_back({points[points.size() - 2], points[points.size() - 1]});

    // 输出结果
    for (auto& point : ans) {
        cout << point[0] << " " << point[1] << " ";
    }
    cout << endl;
    return 0;
}

时空复杂度

时间复杂度:O(N)。仅需一次循环所有点。

空间复杂度:O(1)。仅需若干常数变量。


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

  • 35
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值