最大的观影时间问题

最大,观影,时间,问题 · 浏览次数 : 248

小编点评

**算法和数据结构笔记** **暴力方法** *枚举前三场所有的可能全排列 *时间复杂度O(3^n) **递归解** *记忆化搜索的动态规划 *时间复杂度O(m^n) *m是数组长度,n是时间复杂度 **动态规划** * memo化搜索 *时间复杂度O(m^n) *m是数组长度,n是时间复杂度 **其他** *导入java.util.* *使用Arrays.sort() *使用Math.max() *使用if语句控制分支 *使用swap方法交换数组元素

正文

最大的观影时间问题

作者:Grey

原文地址:

博客园:最大的观影时间问题

CSDN:最大的观影时间问题

题目描述

一场电影开始和结束时间可以用一个小数组来表示["07:30","12:00"]
已知有 2000 场电影开始和结束都在同一天,这一天从 00:00 开始到 23:59 结束
一定要选 3 场完全不冲突的电影来观看,返回最大的观影时间
如果无法选出 3 场完全不冲突的电影来观看,返回 -1

暴力解法

枚举前三场电影的所有的可能全排列,定义如下递归函数

int process1(int[][] movies, int index)

递归含义表示,从 index 开始到最后,任意选三场不冲突的电影,最大观影时间是多少。

首先是 base case,由于是枚举所有可能的排列,所以,任意三场都可能出现在 0,1,2 位置上,所以,base case 就是 index == 3 的时候,可以结算

image

index == 3 的时候,可以结算此时的 0, 1, 2 的电影情况,计算出最大观影时间

            int start = 0;
            int watch = 0;
            for (int i = 0; i < 3; i++) {
                if (start > movies[i][0]) {
                    return -1;
                }
                watch += movies[i][1] - movies[i][0];
                start = movies[i][1];
            }
            return watch;

否则,就是做全排列,全排列算法可以参考这篇博客

            int ans = -1;
            for (int i = index; i < movies.length; i++) {
                swap(movies, index, i);
                ans = Math.max(ans, process1(movies, index + 1));
                swap(movies, index, i);
            }
            return ans;

暴力解法完整代码如下

    public static int maxEnjoy1(int[][] movies) {
        if (movies.length < 3) {
            return -1;
        }
        return process1(movies, 0);
    }

    public static int process1(int[][] movies, int index) {
        if (index == 3) {
            int start = 0;
            int watch = 0;
            for (int i = 0; i < 3; i++) {
                if (start > movies[i][0]) {
                    return -1;
                }
                watch += movies[i][1] - movies[i][0];
                start = movies[i][1];
            }
            return watch;
        } else {
            int ans = -1;
            for (int i = index; i < movies.length; i++) {
                swap(movies, index, i);
                ans = Math.max(ans, process1(movies, index + 1));
                swap(movies, index, i);
            }
            return ans;
        }
    }

    public static void swap(int[][] movies, int i, int j) {
        int[] tmp = movies[i];
        movies[i] = movies[j];
        movies[j] = tmp;
    }

优化后的递归解

首先,对电影进行排序,开始时间在前的排在前面,开始时间一样的,结束时间前的排在前面。

递归函数设计为

int process2(int[][] movies, int index, int time, int rest)

递归含义表示:从 index 一直到最后一部电影,时间点从 0 开始,rest 表示还剩几部电影要选,得到的最大观影时间是多少。

所以 process2(int[][] movies, 0, 0, 3) 就是原题答案。

接下来是 base case,

如果 index == movies.length 表示没有电影可以选,此时,如果 rest == 0 ,表示正好不需要继续选电影,此时可以返回最大观影时间是 0, 否则,返回 -1 ,表示之前的决策有问题。

接下来是普遍情况,有两种决策:

决策一,可以不选 index 位置的电影,直接去 index + 1 位置做决策,即

int p1 = process2(movies, index + 1, time, rest);

决策二,选择 index 位置的电影,但是这个选择有条件,即: movies[index][0] >= time && rest > 0,表示当前电影的开始时间在 time 之后,且剩余要选择的电影大于 0,才能选。否则直接返回 -1,说明这种决策无效,即

        // 电影的开始时间,要小于规定的time时间,且可选的电影要大于0
        int next = movies[index][0] >= time && rest > 0 ? process2(movies, index + 1, movies[index][1], rest - 1) : -1;
        // 如果上述决策是-1,那么可能性2就是-1,如果不是-1,则继续去下一个位置选择。
        int p2 = next != -1 ? (movies[index][1] - movies[index][0] + next) : -1;

综上所述,完整代码如下

    public static int maxEnjoy2(int[][] movies) {
        Arrays.sort(movies, (a, b) -> a[0] != b[0] ? (a[0] - b[0]) : (a[1] - b[1]));
        return process2(movies, 0, 0, 3);
    }

    public static int process2(int[][] movies, int index, int time, int rest) {
        if (index == movies.length) {
            return rest == 0 ? 0 : -1;
        }
        int p1 = process2(movies, index + 1, time, rest);
        int next = movies[index][0] >= time && rest > 0 ? process2(movies, index + 1, movies[index][1], rest - 1) : -1;
        int p2 = next != -1 ? (movies[index][1] - movies[index][0] + next) : -1;
        return Math.max(p1, p2);
    }

使用对数器对上述两种算法进行多次测试,测试通过

import java.util.Arrays;

public class Code_WatchMovieMaxTime {

    // 暴力方法,枚举前三场所有的可能全排列
    public static int maxEnjoy1(int[][] movies) {
        if (movies.length < 3) {
            return -1;
        }
        return process1(movies, 0);
    }

    public static int process1(int[][] movies, int index) {
        if (index == 3) {
            int start = 0;
            int watch = 0;
            for (int i = 0; i < 3; i++) {
                if (start > movies[i][0]) {
                    return -1;
                }
                watch += movies[i][1] - movies[i][0];
                start = movies[i][1];
            }
            return watch;
        } else {
            int ans = -1;
            for (int i = index; i < movies.length; i++) {
                swap(movies, index, i);
                ans = Math.max(ans, process1(movies, index + 1));
                swap(movies, index, i);
            }
            return ans;
        }
    }

    public static void swap(int[][] movies, int i, int j) {
        int[] tmp = movies[i];
        movies[i] = movies[j];
        movies[j] = tmp;
    }

    // 优化后的递归解
    public static int maxEnjoy2(int[][] movies) {
        Arrays.sort(movies, (a, b) -> a[0] != b[0] ? (a[0] - b[0]) : (a[1] - b[1]));
        return process2(movies, 0, 0, 3);
    }

    public static int process2(int[][] movies, int index, int time, int rest) {
        if (index == movies.length) {
            return rest == 0 ? 0 : -1;
        }
        int p1 = process2(movies, index + 1, time, rest);
        int next = movies[index][0] >= time && rest > 0 ? process2(movies, index + 1, movies[index][1], rest - 1) : -1;
        int p2 = next != -1 ? (movies[index][1] - movies[index][0] + next) : -1;
        return Math.max(p1, p2);
    }

    // 记忆化搜索的动态规划

    // 为了测试
    public static int[][] randomMovies(int len, int time) {
        int[][] movies = new int[len][2];
        for (int i = 0; i < len; i++) {
            int a = (int) (Math.random() * time);
            int b = (int) (Math.random() * time);
            movies[i][0] = Math.min(a, b);
            movies[i][1] = Math.max(a, b);
        }
        return movies;
    }

    public static void main(String[] args) {
        int n = 10;
        int t = 20;
        int testTime = 10000;
        System.out.println("测试开始");
        for (int i = 0; i < testTime; i++) {
            int len = (int) (Math.random() * n) + 1;
            int[][] movies = randomMovies(len, t);
            int ans1 = maxEnjoy1(movies);
            int ans2 = maxEnjoy2(movies);
            if (ans1 != ans2) {
                for (int[] m : movies) {
                    System.out.println(m[0] + " , " + m[1]);
                }
                System.out.println(ans1);
                System.out.println(ans2);
                System.out.println("出错了");
            }
        }
        System.out.println("测试结束");
    }
}

更多

算法和数据结构笔记

与最大的观影时间问题相似的内容:

最大的观影时间问题

最大的观影时间问题 作者:Grey 原文地址: 博客园:最大的观影时间问题 CSDN:最大的观影时间问题 题目描述 一场电影开始和结束时间可以用一个小数组来表示["07:30","12:00"] 已知有 2000 场电影开始和结束都在同一天,这一天从 00:00 开始到 23:59 结束 一定要选

[转帖]Java使用火焰图查看系统瓶颈

场景 一般情况下,我们会对现有系统进行压测等方式,来了解系统最大的吞吐量等等,通过这种方式得知系统在生产环境下可扛住的压力,如果我们想了解在压测的链路过程中,是哪些地方执行时间过长,影响了系统的吞吐量,可以使用火焰图的方式来观察。 工具 生成火焰图需要两个工具: 1. async-profiler:

【微信自动化】使用c#实现微信自动化

引言 上个月,在一个群里摸鱼划水空度日,看到了一个老哥分享的一个微信自动化的一个类库,便下载了他的Demo,其本意就是模拟鼠标来操作UI,实现UI自动化;然后自己在瞎琢磨研究,写了一个简单的例子,用来获取好友列表,获取聊天列表,以及最后一次接收或者发送消息的时间,以及最后一次聊天的内容,还有自动刷朋

Redis 菜鸟进阶

Redis 菜鸟进阶 背景 最近产品一直要优化性能,加强高可用. 有一个课题是Redis高可用与性能调优. 我这边其实获取到的内容很有限. 最近济南疫情严重,自己锁骨骨折. 然后通勤时间基本上都用来查资料了. 但是毕竟水平有限..简单整理总结一下. 估计纰漏很多..需要进一步学习. 单点 观点: R

起风了,NCC 云原生项目孵化计划

在经过深思熟虑后,我们计划发起名为wind rises的项目孵化,在 .NET 平台上尽力弥补缺少云原生基础设施项目的遗憾。 在今年的最后几个月和明年,我们规划了使用 .NET 开发的可观测性平台和分布式应用框架两个项目

图数据挖掘:基于概率的流行病模型

这篇博客让我们来介绍基于概率的传播模型,这种模型基于对数据的观测来构建,不过不能对因果性进行建模。基于随机树的传染病模型是分支过程(branching processes)的一种变种。在这种模型中,一个病人可能接触d个其他人,对他们中的每一个都有概率q>0将其传染,接下来我们来看当d和q取何值时,流行病最终会消失(die out)

【c#表达式树】最完善的表达式树Expression.Dynamic的玩法

引言 在我第一次写博客的时候,写的第一篇文章,就是关于表达式树的,链接:https://www.cnblogs.com/1996-Chinese-Chen/p/14987967.html,其中,当时一直没有研究Expression.Dynamic的使用方法(因为网上找不到资料),就了解到是程序运行时

我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈

1、前言 在6.28/29的稀土掘金开发者大会RAG专场上,我们公司CEO员外代表TorchV分享了我们在《RAG在企业应用中落地的难点与创新》 其中最后分享了两个观点: AI在应用场景落地时有三个特点:功能小、质量高、价值大 如果说做产品是把一横做好的话,那么去做企业落地服务就是一竖,从需求和方案

[转帖]请求量突增一下,系统有效QPS为何下降很多?

https://www.cnblogs.com/codelogs/p/17056485.html 原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。 简介# 最近我观察到一个现象,当服务的请求量突发的增长一下时,服务的有效QPS会下降很多,有时甚至会降到0,这种现象网上也

[转帖] 请求量突增一下,系统有效QPS为何下降很多?

https://www.cnblogs.com/codelogs/p/17056485.html 原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。 简介# 最近我观察到一个现象,当服务的请求量突发的增长一下时,服务的有效QPS会下降很多,有时甚至会降到0,这种现象网上也