力扣日记1494

news2024/11/17 2:45:14

1. 题目

[LeetCode 1494. 并行课程 II]https://leetcode.cn/problems/parallel-courses-ii/)

1.1 题意

严格按照选课先修顺序选课,每个学期选课数有上限,求选完所有课程的最短学期数

1.2 分析

这道题的数据量很小,而且作为困难题,开始考虑是不是用暴力递归。

1 <= n <= 15

事实上,我在写的时候大意了没有闪,把他看成一个拓扑排序,觉得依次把入度为0的课程选择即可。

第60个测试样例直接错。意识到每个学期选择的入度为0的课程是有影响的。那么递归直接忽略,先考虑可否贪心。

能不能每次贪心选择入度为0,但出度尽可能大的节点呢?这样可以使得剩下的图的边数减少的更多。
思考一下,设想一个极限场景:有一条关键路径上有很多课程,但是都只受限于一个出度为1,入度为0的课程,这样这条路径会被“饿死”,被选择到的时间很晚,这并不是最优的方法。(下图举例,下图是可以在5个学期被选完的,关键取决于第一个学期的选择)
举个栗子
排除了贪心就考虑动态规划,

第一个问题,怎么存信息?最多只有15个课程,可以使用状态压缩的方法,利用n位one-hot编码(int变量即可)来表示每个课程是否已经被修过。

第二个问题,怎么递推?由状态信息(存的是该情况下已经修过的课程和没有修过的课程),查找此情况下入度为0的节点,如果节点数小于等于k则选上所有课程,节点数大于k需要做一个 C N k C_{N}^{k} CNk 从入度为0的节点中选取k个节点,并且把所有的情况都遍历一遍,这里可以使用dfs去做。为了防止出现重复状态可以使用set做容器

1.3 我的解法

class Solution {
public:
    void dfs(int vis, int ind, int k, int chooseNum, vector<int> &node,set<int> &st){
        // 细节第一个递归边界在第二个递归边界前
        // 不然会缺少情况
        if(chooseNum == k){
            // 选到了足够的课程
            st.insert(vis);
            return;
        }
        // 所有情况都已经遍历
        if(ind >= node.size()){
            return;
        }

        // not choose
        // 不选择课程
        dfs(vis, ind+1, k, chooseNum, node, st);
        // choose
        // 选择该课程
        // 这里注意位运算优先级顺序 都打上括号
        if( ( vis | (1<<node[ind]) ) != vis)
            // 简单的剪枝
            // 即该课程未被选过
            dfs(vis|(1<<node[ind]), ind+1, k, chooseNum+1, node, st);
    }
    int minNumberOfSemesters(int n, vector<vector<int>>& relations, int k) {
        // 状态压缩
        // 这里实际可以使用两个set
        vector<set<int> > state;
        // 初始化
        state.emplace_back(set<int>{0} );
        int res = 0;
        int m = relations.size();
        while(1){
            res++; // 统计学期数
            set<int> st;
            for(auto it = state.back().begin(); it != state.back().end(); it++){
                // 每一次要把前一个学期所有的情况都做一遍计算
                int vis = *it;
                // get in degree
                // 计算入度
                vector<int> inDegree(n+1, 0);
                for(int i=0; i<m; i++){
                    // not vis
                    // 位运算细节,表示没有修该课程
                    if((vis & (1 << relations[i][0]) ) == 0 ){
                        inDegree[relations[i][1]]++;
                    }
                }
                // 查找入度为0 并且没有访问的节点
                // find node: inDegree = 0
                vector<int> node;
                for(int i=1;i<=n;i++){
                    if(inDegree[i] == 0 && ( ( vis & (1<<i) ) == 0) ){
                        // not vis
                        node.emplace_back(i);
                    }
                }
                // 如果可选课程不足k,全选
                if(node.size()<=k){
                    for(int i:node){
                        vis |= (1<<i);
                    }
                    st.insert(vis);
                }else{
                    // choose node 
                    // combine and arrange all cases
                    // 可选课程较多,做排列组合,遍历所有情况
                    dfs(vis, 0, k, 0, node, st);
                }
            }
            if(st.find( (1<<(n+1)) - 2 ) != st.end()){
                // 判断有没有全部修读的情况
                // 有可以直接结束,(这个感觉有点像bfs
                // (1<<(n+1)) - 2 注意运算优先级
                // 我使用的是从第1位到第n位来表示是否访问过该节点
                // 所有节点都访问的情况应该是 第1~n位为1 其余位为0
                // (1<<(n+1)) - 1 是第0~n位全为1
                // 再减1 第0位也是0了
                break;
            }
            else{
                state.emplace_back(st);
            }
        }
        return res;
    }
};

1.4 学习题解反思

时间复杂度分析:
最外层循环最多n次(一学期修一门课程)
set一层的循环,每次的状态最多是 C n k C_{n}^{k} Cnk(所有课程都可以直接选)
内层找入度、节点的,最多次是边的数目: n * (n-1) / 2
然后node中做dfs的部分上界为2^n(两种情况,深度为node的大小)
最后乘再一起 n 3 ∗ 2 n ∗ C n k n^3*2^n*C_{n}^{k} n32nCnk 这其实是个不确切的上界
空间复杂度分析:
最坏情况下n次循环,然后每次最多装 C n k C_{n}^{k} Cnk个状态
(其实这里可以把前面的n去掉,因为每次都之和前一个学期状态有关,用两个set循环替也是可以)

题解学习:g 没学

2.4 bug日记

2.4.1 思路想错

2.4.2 位运算优先级

2. 后记

每日困难题坐牢 人菜瘾大多练
仅分享自己的想法,有意见和指点非常感谢

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

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

相关文章

一起学 WebGL:纹理对象学习

大家好&#xff0c;我是前端西瓜哥&#xff0c;今天我们来了解 WebGL 的纹理对象&#xff08;Texture&#xff09; 纹理对象&#xff0c;是将像素&#xff08;texels&#xff09;以数组方式传给 GPU 的对象&#xff0c;常见场景是贴图&#xff0c;就是将图片的数据应用到 3D 物…

vue 根据word摸板导出word文档,并压缩为zip

yarn add jszip3.10.1 yarn add jszip-utils0.1.0 yarn add pizzip3.1.4 yarn add docxtemplater3.29.5 yarn add docxtemplater-image-module-free1.1.1 yarn add file-saver2.0.5 注意&#xff1a;这里的fileUrl必须是绝对路径&#xff0c;否则可能会报 is not zip的错误&…

当pytest遇上poium会擦出什么火花

当pytest遇上poium会擦出什么火花 首先&#xff0c;创建一个test_sample/test_demo.py 文件&#xff0c;写入下面三行代码。 def test_bing(page):page.get("https://www.bing.com")assert page.get_title "必应"不要问题 page 从哪里来&#xff0c;打开…

(LLM) 的所有知识;10分钟了解向量数据库;微软 Bing 可以识别图片了;

&#x1f989; AI新闻 &#x1f680; 微软 Bing 可以识图」了&#xff0c;吊打 GPT-4&#xff1f; 摘要&#xff1a;微软 Bing 最新识图功能让用户可以上传图片并进行编程、做题、看病等操作&#xff0c;还能分析梗图笑点。然而在某些情况下表现不佳&#xff0c;例如无法数清…

技术分享 | i.MX8M Plus开发板 固定IP地址以及单网口多IP设置

以启扬IMX8MP开发板为例&#xff0c;给大家分享固定IP地址以及单网口多IP设置的步骤流程。 固定IP地址设置 20-wired.network 重启Network生效 网口多ip设置 对于一些网络管理的命令 connman设置&#xff08;参考&#xff09; imx8 yocto系统的init system使用systemd&#xff…

精选Java SSM 框架基础面试题

一、Spring面试题 1、Spring 在ssm中起什么作用&#xff1f; Spring&#xff1a;轻量级框架作用&#xff1a;Bean工厂&#xff0c;用来管理Bean的生命周期和框架集成。两大核心&#xff1a;1、IOC/DI(控制反转/依赖注入) &#xff1a;把dao依赖注入到service层&#xff0c;se…

STM32 GPIO 详解

0. 实验平台 基于STM32F407ZG 1. GPIO 简介 1.1 简介 GPIO全称&#xff1a;General Purpose Input Output&#xff0c;即通用输入输出端口&#xff0c;一般用来采集外部器件的信息或者控制外部器件工作&#xff0c;即输入输出 1.2 STM32 的 GPIO 特点 不同型号&#xff0…

SpringBatch从入门到实战(五):执行上下文和单步骤重启

一&#xff1a;执行上下文 1.1 Job Context 作业上下文 JobContext 绑定 JobExecution 执行对象&#xff0c;为Job作业执行提供执行环境(上下文)。 1.2 Step Context 步骤上下文 StepContext 绑定 StepExecution 执行对象&#xff0c;为Step步骤执行提供执行环境(上下文)。 …

【剑指offer专项突破版】栈篇——“C“

文章目录 前言一、后缀表达式题目分析思路分析代码 二、小行星碰撞题目分析思路分析代码 三、每日温度题目分析思路分析代码 四、直方图最大矩形面积题目分析思路分析代码 五、矩阵中最大的矩形题目分析思路分析代码 总结 前言 剑指offer专项突破版&#xff08;力扣官网&#x…

IBM不藏私:深刻解析量子计算机的突破和机遇

​ 巴伐利亚科学部长Markus Blume在莱布尼茨超级计算中心与Dieter Kranzlmlle&#xff08;左&#xff09;一起观看量子计算机的部分构件。&#xff08;图片来源&#xff1a;网络&#xff09; 关于量子计算机的研究已进行了数十年&#xff0c;目前还尚未生产一台能够掀起计算革命…

Vue全家桶(一):Vue基础+Vue-Cli+Vue组件化+过渡动画

目录 1.Vue概述1.1 认识Vue1.2 Vue的两核心1.3 Vue的初体验1.4 Vue的生命周期 2. Vue-CLI (Command Line Interface)3. Vue基本使用3.1 传统开发模式对比3.2 Vue.js引入3.3 Vue.js 案例分析3.3.1 实例参数el、data、methods的写法 4. Vue模板语法4.1 插值语法 {{xxx}}4.2 指令语…

vue3+ts:shims-vue.d.ts

一、本文引子 uniapp&#xff08;3.8.4.20230531&#xff09; vue3 ts vite 项目 在搭建这个base项目的时候出现红素波浪线如图&#xff0c;代码运行正常&#xff0c;但是看起来很难受&#xff0c;于是各种查找&#xff0c;能找到的资料很少&#xff0c;可能和我提问不够准…

【备战秋招】每日一题:4月23日美团春招第一题:题面+题目思路 + C++/python/js/Go/java带注释

为了更好的阅读体检&#xff0c;为了更好的阅读体检&#xff0c;&#xff0c;可以查看我的算法学习博客第一题-申请奖学金 在线评测链接:P1245 题目内容 塔子哥是一个热爱学习的大学生&#xff0c;他的梦想是成为一名优秀的算法竞赛高手。为了实现自己的梦想&#xff0c;他需…

代理ip匿名原理及那些行业需要代理ip

互联网的高速发展&#xff0c;连带了代理ip也受到了更多人的使用&#xff0c;不同的行业都存在使用代理ip的情况&#xff0c;同时代理ip也以为匿名程度分成了高匿、普匿、透明代理&#xff0c;那么代理ip匿名的原理是什么呢&#xff1f;又有哪些行业需要代理ip呢&#xff1f;下…

flume环境配置-传输Hadoop日志(namenode或datanode日志)

解压文件 修改文件名 配置环境变量 执行flume-ng version 将flume-env.sh.template改名为flume-env.sh&#xff0c; 并修改其配置 启动Flume传输Hadoop日志 启动flume 解压文件 tar -zxvf apache-flume-1.9.0-bin.tar.gz -C /opt 修改文件名 mv apache-flume-1.9.0-b…

全面安全防护,加速企业创新发展——亚马逊云科技re:Inforce全球大会

亚马逊云科技re:Inforce 2023全球大会于当地时间2023年6月13日在美国加州安纳海姆拉开帷幕。在大会上&#xff0c;亚马逊云科技宣布推出十多项安全新服务及功能&#xff0c;下面就来一览本次大会的风采。 “Security is our top priority.” “安全是我们的首要优先级”&#…

Java 面向对象 | 详细知识图谱式讲解

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; ☢Java入门 基础知识&#xff1a;了解 Java 基本语法、面向对象编程&#xff08;OOP&#xff09;概念、流程控制语句、数据类型、方法等基础知识。可以通过 Java 编程…

Nodejs七、身份认证

零、文章目录 Nodejs七、身份认证 1、Web 开发模式 &#xff08;1&#xff09;目前主流的 Web 开发模式 基于服务端渲染的传统 Web 开发模式基于前后端分离的新型 Web 开发模式 &#xff08;2&#xff09;服务端渲染的 Web 开发模式 服务器发送给客户端的 HTML 页面&…

HBase Shell操作HBase进行预分区

本文将介绍如何使用HBase Shell操作HBase进行预分区。预分区是指在创建表的时候&#xff0c;指定表的初始分区点&#xff0c;从而使表的数据能够均匀地分布在多个RegionServer上&#xff0c;提高读写性能和负载均衡。本文将使用HBase Shell命令&#xff0c;创建不同的预分区表&…

Allure在自动化测试中的应用

目录 前言&#xff1a; 01Allure的简介及使用 1、应用场景 02Allure与Pytest结合 1、添加测试步骤 2、添加主要功能模块描述 3、添加严重等级 03Allure集成Jenkins 1、Jenkins介绍和安装 2、Jenkins安装allure插件 前言&#xff1a; Allure是一种流行的测试报告框架…