【限时免费】20天拿下华为OD笔试之【DP/贪心】2023B-观看文艺汇演-200分【欧弟算法】全网注释最详细分类最全的华为OD真题题解

news2024/11/26 8:23:03

【DP/贪心】2023B-观看文艺汇演

题目描述与示例

某公园将举行多场文艺表演,很多演出都是同时进行,一个人只能同时观看一场演出,且不能迟到早退,由于演出分布在不同的演出场地,所以连续观看的演出最少有 15 分钟的时间间隔,小明是一个狂热的文艺迷,想观看尽可能多的演出。现给出演出时间表,请帮小明计算他最多能观看几场演出。

输入

第一行为一个数 N,表示演出场数,1 <= N <= 1000

接下来 N 行,每行两个空格分割的整数,第一个整数 T 表示演出的开始时间,第二个整数 L 表示演出的结束时间,TL 的单位为分钟,0 <= T <= 1440, 0 < L <= 100

输出

最多能观看的演出场数。

示例一

输入

2
720 120
840 120

输出

1

说明

第一场演出开始时间是第 720 分钟,经过 120 分钟演出结束,即第 840 分钟结束,此时还需要 15 分钟的间隔时间,即要等到第 855 分钟才可以看下一场演出,故来不及看第二场在第 840 分钟开始的演出。最多只能看 1 场演出。

示例二

输入

2
20 60
100 60

输出

2

说明

第一场演出开始时间是第 20 分钟,经过 60 分钟演出结束,即第 80 分钟结束,此时还需要 15 分钟的间隔时间,即要等到第 95 分钟才可以看下一场演出,第二场演出在第 100 分钟开始的演出,赶得上观看第二场演出。最多可以观看 2 场演出。

示例三

输入

4
10 20
100 20
150 60
80 40

输出

3

解题思路

注意,本题和 LC435. 无重叠区间几乎完全一致。

原始数据处理

我们可以储存每一场演出的开始和结束时间,即按照 [start, end] 的方式进行储存,储存在列表 intervals 中。由于题目要求每间隔 15 分钟才能够看下一场演出,所以我们可以把每一场演出的结束时间再加上 15 分钟,这样题目就转变为:考虑所有不重叠的 [start, end] 区间的最大数目。处理输入的代码如下

N = int(input())
intervals = list()
for _ in range(N):
    start, during = map(int, input().split())
    end = start + during + 15
    intervals.append((start, end))

贪心思想求解问题

为了方便我们贪心地思考问题,我们先按照开始时间 start 从小到大对间隔列表 intervals 进行排序。然后我们考虑相邻的两场演出,[start1, end1][start2, end2],由于 intervals 已经排序,必然存在 start1 <= start2 成立,故这两场演出之间的关系存只有以下三种可能性

  1. start1 < end1 <= start2 < end2,即演出 2 的开始时间在演出 1 的结束时间之后。故看完演出 1,可以继续看演出 2
  2. start1 <= start2 <= end1 <= end2,即演出 2 的开始时间在演出 1 的结束时间之前,但演出 2 的结束时间在演出 1 的结束时间之后。故看完演出 1 之后,没办法观看演出 2
  3. start1 <= start2 <= end2 <= end1,即演出 2 的开始时间和结束时间均在演出 1 的结束时间之前。故看完演出 1 之后,没办法观看演出 2。为了尽可能多地看更多的演出,选择演出 2 来观看会比选择演出 1 更好,因为演出 2 的结束时间更早,有充裕的时间去观看后续的演出。

理解了相邻两场演出的三种可能性之后,我们发现解决问题的关键实际上在于考虑演出 1 的结束时间 end1 和演出 2 的间隔 [start2, end2] 之间的关系:

  1. end1[start2, end2] 之前
    在这里插入图片描述

  2. end1[start2, end2] 之间
    在这里插入图片描述

  3. end1[start2, end2] 之后
    在这里插入图片描述

由于我们需要遍历排序后的间隔列表 intervals 中的每一个间隔 [start, end],因此可以维护变量 pre_end,表示上一场演出的结束时间。初始化 pre_end = -inf,表示第一场演出始终可以观看。

考虑当前间隔 [start, end] 和上一场演出结束时间 pre_end 之间的关系,我们可以得到以下逻辑:

  1. pre_end[start, end] 之前,我们可以选择当前的演出 [start, end] 进行观看

    • 能观看的演出场次 ans += 1
    • 由于选择了 [start, end] 进行观看,下一场演出的观看时间应该由当前的 end 决定,即对于下一场演出而言,当前结束时间 end 是上一场演出的结束时间,故更新 pre_end = end
  2. pre_end[start, end] 之间,我们不能选择当前的演出 [start, end] 进行观看

    • 由于 pre_end ≤ end,因此我们保留之前的 pre_end,作为判断下一场演出是否能观看的依据。故无需做任何事情。
  3. pre_end[start, end] 之后,我们不能选择当前的演出 [start, end] 进行观看

    • 由于 pre_end > end,选择 end 作为判断下一场演出是否能观看的依据是更佳的选择,即我们不去选择观看 pre_end 所对应的之前某场演出,而选择观看当前的演出 [start, end],这样的选择有利于后面留出充裕的时间来尽可能地观看更多演出,故更新 pre_end = end

整理上述逻辑后,代码为

for start, end in intervals:
    if start >= pre_end:
        ans += 1
        pre_end = end
    elif start < pre_end <= end:
        continue
    elif pre_end > end:
        pre_end = end

动态规划求解问题

实际上,当我们对间隔列表 intervals 排序之后,我们也可以把这个问题当作经典的 LIS 问题(LC300. 最长递增子序列)进行处理。
在这里插入图片描述

譬如对于上述例子,我们所选的演出应该为演出 145
在这里插入图片描述

换句话说,我们需要找到尽可能多的演出区间,所有演出区间均需要满足 start ≥ pre_end,其中 start 为第 i 个区间的开始时间,pre_end 为上一个区间即第第 i-1 个区间的结束时间。这是一个非常自然的 LIS 问题,故也可以用 dp 来解决问题。

我们考虑动态规划三部曲:

  1. dp数组的含义是什么?
  • dp 数组是一个长度为 n 的一维列表,dp[i] 表示包含了第 i 场演出 intervals[i] 的最长无重叠演出数目。
  1. 动态转移方程是什么?
  • 包含了第 i 场演出 intervals[i] 的最长无重叠演出数目,由前面的 i-1 场演出中(用索引 j 表示),结束时间 intervals[j][1] 小于当前演出开始时间 intervals[i][0]dp[j] 最大的那场演出决定。
for i in range(1, N):
    temp = 0
    for j in range(i):
        if intervals[j][1] <= intervals[i][0]:
            temp = max(dp[j], temp)
    dp[i] = temp + 1
  1. dp数组如何初始化?
  • 包含第 1 场演出的最长无重叠演出数目为 1
dp[0] = 1

代码

解法一:贪心

Python

# 题目:2023B-观看文艺汇演
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:贪心
# 代码看不懂的地方,请直接在群上提问


from math import inf

# 输入演出的数目
N = int(input())

# 初始化间隔列表
intervals = list()
for _ in range(N):
    start, during = map(int, input().split())
    # 对于每一个结束时间都+15后再储存,方便后续进行比较
    end = start + during + 15
    intervals.append((start, end))
    
# 对intervals进行排序
intervals.sort()
ans = 0

# 初始化【上个区间结束时间】为pre_end = -inf
pre_end = -inf

# 遍历所有区间的起始时间和结束时间
for start, end in intervals:
    # 如果【当前起始时间】大于等于【上次结束时间】
    # 可以选择【当前区间】进行观看,接在【上个区间】后面
    # 同时 pre_end 应该修改为【当前结束时间】
    # 作为下一个区间的【上次结束时间】
    if start >= pre_end:
        ans += 1
        pre_end = end
    # 如果【上次结束时间】正好落在【当前区间】内
    # 则不能选择【当前区间】进行观看,保留【上个区间】
    # 无需做任何事情
    elif start < pre_end <= end:
        continue
    # 如果【上次结束时间】大于【当前结束时间】
    # 则应该选择【当前区间】进行观看,而不应该选择【上个区间】
    # 故 pre_end 应该修改为【当前结束时间】
    # 作为下一个区间的【上次结束时间】
    elif pre_end > end:
        pre_end = end

print(ans)

Java

import java.util.*;

class Interval implements Comparable<Interval> {
    int start;
    int end;

    public Interval(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public int compareTo(Interval other) {
        return this.start - other.start;
    }
}

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

        List<Interval> intervals = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            int start = scanner.nextInt();
            int during = scanner.nextInt();
            int end = start + during + 15;
            intervals.add(new Interval(start, end));
        }

        Collections.sort(intervals);

        int ans = 0;
        int preEnd = Integer.MIN_VALUE;

        for (Interval interval : intervals) {
            int start = interval.start;
            int end = interval.end;

            if (start >= preEnd) {
                ans++;
                preEnd = end;
            } else if (start < preEnd && preEnd <= end) {
                continue;
            } else if (preEnd > end) {
                preEnd = end;
            }
        }

        System.out.println(ans);
    }
}

C++

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Interval {
    int start;
    int end;

    Interval(int s, int e) : start(s), end(e) {}
};

bool compareIntervals(const Interval& a, const Interval& b) {
    return a.start < b.start;
}

int main() {
    int N;
    cin >> N;

    vector<Interval> intervals;
    for (int i = 0; i < N; ++i) {
        int start, during;
        cin >> start >> during;
        int end = start + during + 15;
        intervals.push_back(Interval(start, end));
    }

    sort(intervals.begin(), intervals.end(), compareIntervals);

    int ans = 0;
    int preEnd = -1e9;

    for (const auto& interval : intervals) {
        int start = interval.start;
        int end = interval.end;

        if (start >= preEnd) {
            ans++;
            preEnd = end;
        } else if (start < preEnd && preEnd <= end) {
            continue;
        } else if (preEnd > end) {
            preEnd = end;
        }
    }

    cout << ans << endl;

    return 0;
}

时空复杂度

时间复杂度:O(NlogN)。排序时间复杂度。

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

解法二:DP

Python

# 题目:2023B-观看文艺汇演
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:dp(LIS问题)
# 代码看不懂的地方,请直接在群上提问


# 输入演出的数目
N = int(input())

# 初始化间隔列表
intervals = list()
for _ in range(N):
    start, during = map(int, input().split())
    # 对于每一个结束时间都+15后再储存,方便后续进行比较
    end = start + during + 15
    intervals.append((start, end))

# 对intervals进行排序
intervals.sort()
ans = 0

# 初始化长度为N的dp数组
dp = N * [0]
# 包含第1场演出的最长无重叠演出数目为1
dp[0] = 1

# 遍历所有演出
for i in range(1, N):
    # 初始化变量temp,用于找到前面的i-1场演出中,最长无重叠的演出场次
    temp = 0
    # 对于每一场演出i,遍历其前面的i-1场演出
    for j in range(i):
        # 如果演出j的结束时间,小于等于当前演出i的开始时间
        if intervals[j][1] <= intervals[i][0]:
            # 则更新temp
            temp = max(dp[j], temp)
    # 结束上述循环后,还需要考虑本场演出本身
    dp[i] = temp + 1


# dp数组中的最大值,即为最长无重叠的演出场次
# 也就是能够观看的最多的演出场次
print(max(dp))

Java

import java.util.*;

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

        List<int[]> intervals = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            int start = scanner.nextInt();
            int during = scanner.nextInt();
            int end = start + during + 15;
            intervals.add(new int[]{start, end});
        }

        intervals.sort(Comparator.comparingInt(a -> a[0]));

        int[] dp = new int[N];
        dp[0] = 1;

        for (int i = 1; i < N; i++) {
            int temp = 0;
            for (int j = 0; j < i; j++) {
                if (intervals.get(j)[1] <= intervals.get(i)[0]) {
                    temp = Math.max(dp[j], temp);
                }
            }
            dp[i] = temp + 1;
        }

        int maxWatch = Arrays.stream(dp).max().orElse(0);
        System.out.println(maxWatch);
    }
}

C++

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int N;
    cin >> N;

    vector<pair<int, int>> intervals;
    for (int i = 0; i < N; ++i) {
        int start, during;
        cin >> start >> during;
        int end = start + during + 15;
        intervals.push_back({start, end});
    }

    sort(intervals.begin(), intervals.end());

    vector<int> dp(N, 0);
    dp[0] = 1;

    for (int i = 1; i < N; ++i) {
        int temp = 0;
        for (int j = 0; j < i; ++j) {
            if (intervals[j].second <= intervals[i].first) {
                temp = max(dp[j], temp);
            }
        }
        dp[i] = temp + 1;
    }

    int maxWatch = *max_element(dp.begin(), dp.end());
    cout << maxWatch << endl;

    return 0;
}

时空复杂度

时间复杂度:O(N^2)。dp过程需要进行双重循环。

空间复杂度:O(N)。dp数组所占空间。


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

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

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

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1255169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

难怪被人卷了不知道啊!这么学自动化测试,一个星期就搞定了!!!

目前自动化测试并不属于新鲜的事物&#xff0c;或者说自动化测试的各种方法论已经层出不穷&#xff0c;但是&#xff0c;能够明白自动化测试并很好落地实施的团队还不是非常多&#xff0c;我们接来下用通俗的方式来介绍自动化测试…… 首先我们从招聘岗位需求说起。看近期的职…

[论文阅读]CBAM——代码实现和讲解

CBAM 论文网址&#xff1a;CBAM 论文代码&#xff1a;CBAM 本文提出了一种卷积块注意力模块&#xff08;CBAM&#xff09;&#xff0c;它是卷积神经网络&#xff08;CNN&#xff09;的一种轻量级、高效的注意力模块。该模块沿着通道和空间两个独立维度依次推导注意力图&#x…

探索深度学习:从理论到实践的全面指南

探索深度学习&#xff1a;从理论到实践的全面指南 摘要&#xff1a; 本文旨在提供一个关于深度学习的全面指南&#xff0c;带领读者从理论基础到实践应用全方位了解这一技术。我们将介绍深度学习的历史、基本原理、常用算法和应用场景&#xff0c;并通过Python代码示例和Tens…

Grafana采用Nginx反向代理

一、场景介绍 在常规操作中&#xff0c;一般情况下不会放开许多端口给外部访问&#xff0c;特别是直接 ip:port 的方式开放访问。但是 Grafana 的请求方式在默认情况下是没有任何规律可寻的。 为了满足业务需求&#xff08;后续通过 Nginx 统一一个接口暴露 N 个服务&#xf…

WordPress最廉价优化整站的加载速度

为什么说一个站不优化就等于一个人做整个团队的事务导致项目进展慢&#xff0c;网站也是如此 图片、静态文件、php分离加速&#xff0c;加载速度并不是很快但是很协调比单个网站加载速度快许多 一、图片单域名加载设置上传文件路径和域名 以下代码添加在主题目录&#xff1a;fu…

PyQt6实战开发之旅-代码均可运行

学习感悟 由于官方文档是英文的&#xff0c;所以学习起来不是很直观。网上的中文教程也都有点偏重就轻&#xff0c;去从头学习细枝末节不是很必要。假如每个控件组件讲十分钟&#xff0c;几百个控件可想而知。最关键的是有python基础&#xff0c;能理解类与继承&#xff0c;函…

leetcode9.回文数

回文数 0.题目1.WJQ的思路2.实现过程2.0 原始值怎么一个个取出来&#xff1f;2.1 取出来的数如何存到新的数字后面&#xff1f;2.2完整的反转得到新数的过程 3.完整的代码4.可运行的代码5.算法还可以优化的部分 0.题目 给你一个整数 x &#xff0c;如果 x 是一个回文整数&…

基于STC12C5A60S2系列1T 8051单片按页写IIC总线器件24C02并显示在液晶显示器LCD1602上应用

基于STC12C5A60S2系列1T 8051单片机按页写IIC总线器件24C02并显示在液晶显示器LCD1602上应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显示器LCD1602简单介绍…

开通橱窗还能开抖店吗?怎么开通?一篇详解!

我是电商珠珠 开通商品橱窗之后还能开抖店吗&#xff1f;商品橱窗和抖音小店可以同时开吗&#xff1f; 一部分人最初的时候&#xff0c;都觉得直播带货很火&#xff0c;所以就自己去买粉丝或是发视频积攒粉丝&#xff0c;等粉丝够了发现&#xff0c;好像和当初想的不太一样&a…

docker (简介、dcoker详细安装步骤)- day01

一、 为什么出现 Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build&#xff0c;Ship and Run Any App,Anywhere”&#xff0c;也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理&#xff0c;使用户的APP&#xff08;可以是一个WEB应用或数据库应…

Java基于springboot+vue开发服装商城小程序

演示视频&#xff1a; 小程序 https://www.bilibili.com/video/BV1rM411o7m4/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 管理员 https://www.bilibili.com/video/BV1fc411D7V3/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae…

【Python爬虫实战项目】ip代理池项目原理及代码解析

视频讲解链接&#xff1a;https://www.bilibili.com/video/BV1e8411r7xX/ 代码链接&#xff1a;https://github.com/w-x-x-w/Spider-Project 大家好&#xff0c;这一季我们来介绍一个Python爬虫实战项目-ip代理池项目&#xff0c;这一集我们会首先介绍ip代理池的工作原理流程&a…

一文讲明SpringMVC 【爆肝整理一万五千字】

我 | 在这里 &#x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 &#x1f3e0; 工作 | 广州 ⭐ Java 全栈开发&#xff08;软件工程师&#xff09; &#x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 ✈️已经旅游的地点 | 新疆-乌鲁木齐、新疆-吐鲁番、广东-广州…

代理模式-C语言实现

UML图&#xff1a; 代码实现&#xff1a; #include <stdio.h>// 抽象主题接口 typedef struct {void (*request)(void*); } Subject;// 具体主题类 typedef struct {void (*request)(void*); } RealSubject;void RealSubject_request(void* obj) {printf("RealSubj…

印度客户来访广东育菁装备考察桌面型数控机床

印度客户来访广东育菁装备考察桌面型数控机床&#xff0c;这是一个重要的商业活动&#xff0c;对于育菁装备来说&#xff0c;这是一个展示产品和技术实力&#xff0c;拓展国际市场的好机会。 在接待印度客户的过程中&#xff0c;育菁装备需要做好充分的准备&#xff0c;包括&am…

整顿国产剧流水线“村花”?给三次元一点小小的美女震撼!

演员部分不符合角色的形象就用配角来补充说明&#xff0c;在国产剧里&#xff0c;短时间出现了两次。 演员的美从直观的肉眼可见&#xff0c;变成了配角用台词传达的结果。 &#xff08;图&#xff1a;宁安如梦&#xff09; 就像《以爱为营》里&#xff0c;女主的闺蜜随口就是…

PTA-7-55 判断指定字符串是否合法

题目&#xff1a; 输入一个字符串&#xff0c;判断指定字符串是否合法&#xff0c;要求字符串由7个字符组成&#xff0c;并且第一位必须是大写字母&#xff0c;2-4为必须是小写字母&#xff0c;后3为必须是数字字符&#xff0c;要求使用正则表达式来实现。 根据题目要求&#x…

storyBook常见踩坑报错 和 解决

用StoryBook官网的代码&#xff0c;但报错&#xff0c;Unexpected token’<’ 在js文件中// Button.stories.js|jsx import { Button } from ‘./Button’; export default { component: Button, }; /* *&#x1f447; Render functions are a framework specific featur…

C语言——深入理解指针(2)

目录 1. 数组名 2. 指针访问数组 3. 一维数组的传参&#xff08;本质&#xff09; 4. 冒泡排序 5. 二级指针 6. 指针数组&#xff08;指针的数组&#xff09; 7. 指针数组模拟二维数组 1. 数组名 在之前的代码中我们使用指针访问过数组的内容。 int arr[10] {1,2,3,4…

DDD(领域驱动设计)一些基础概念

DDD、微服务和中台之间的关系 DDD、微服务和中台之间的关系。 中台本质是业务模型&#xff0c;微服务是业务模型的系统落地&#xff0c;DDD 是一种设计思想&#xff0c;可以同时指导中台业务建模和微服务设计&#xff0c;它们之间就是这样的一个铁三角关系。DDD 强调领域模型…