Leetcode第284场周赛

绪论

最近发现Leetcode每周的周赛难度挺适合我的,而且时间也比较友好(不像Codeforces每次都是半夜)。所以连续参加了三周的周赛。这次才想起来应该记录一下自己的参赛历程。一方面是总结经验,另一方面有了记录就更有动力去提升,去参加下一次比赛。
在这里插入图片描述

题目分析

题目链接:https://leetcode-cn.com/contest/weekly-contest-284/
还是往常一样四道题,难度依次提升。

A:找出数组中的所有 K 近邻下标

简单模拟,对于每一个key,其附近的2k+1个元素都是合法的,需要注意处理重复。为此我们用一个last变量进行记录上一次记录的最后一个元素的位置。

namespace A {class Solution {public:vector<int> findKDistantIndices(vector<int>& nums, int key, int k) {vector<int> ret;int n = nums.size();int last = -1;auto add = [&](int l, int r) {r = min(r, n - 1);l = max(l, last + 1);for (; l <= r; ++l) ret.push_back(l);last = r;};for (int i = 0; i < n; ++i) {if (nums[i] == key) {add(i - k, i + k);}}return ret;}};
}

B:统计可以提取的工件

也是简单模拟,因为数据量比较小,所以无脑做就可以。如果数据量比较大可能是一道比较有意思的题。

namespace B {class Solution {public:int digArtifacts(int n, vector<vector<int>>& artifacts, vector<vector<int>>& dig) {vector<vector<bool>> vis(n, vector<bool>(n));for (auto &pr : dig) {vis[pr[0]][pr[1]] = true;}int x0, x1, y0, y1;int ans = 0;auto check = [&](auto &&tool) -> bool {x0 = tool[0]; y0 = tool[1]; x1 = tool[2]; y1 = tool[3];for (int i = x0; i <= x1; ++i) {for (int j = y0; j <= y1; ++j) {if (!vis[i][j]) return false;}}return true;};for (auto &tool : artifacts) {if (check(tool)) ++ans;}return ans;}};
}

C:K 次操作后最大化顶端元素

这个题如果还是想要通过模拟去做那么就会毫无头绪。因为观察到最后要求的是栈顶的元素最大。而我们如何进行这k次操作的情况是非常多的,我们应该观察哪些元素可以通过k次操作放到栈顶。
假如对栈中的元素从1开始编号。如果我们直接出栈k次,那么是可以得到第k+1个元素的,这个也是我们能够看到的最后一个值。
对1到k-1个元素,我们都可以通过将他们的在最后一步入栈从而让他们放到栈顶。
需要进行讨论的就是我们能够让第k个元素放到栈顶?答案是不行(可以通过简单模拟验证一下)。下面我们简单证明一下。
为了让第k个元素放到栈顶,我们必须弹出前k-1个操作,这样我们就只能再操作一下,而一下无论是弹出还是插入都不能让第k个元素放到栈顶。

经过上面的讨论,我们发现,其实题目的意思就是让我们去找前k+1个元素除去第k个元素的最大值。

但是还需要注意的一点是当n为1的情况(有时间我再证明一下,当时没怎么想清楚在这里还wa了一发)

namespace C {/** 前k - 1的最大值肯定可以取到* 第k个元素取不到* 第k + 1个元素可以取到*/class Solution {public:int maximumTop(vector<int>& nums, int k) {int n = nums.size();if (n == 1 && (k % 2 == 1)) return -1;int ans = -1;int kk = min(k - 1, n);for (int i = 0; i < kk; ++i) {ans = max(ans, nums[i]);}if (k < n) {ans = max(ans, nums[k]);}return ans;}};
}

D:得到要求路径的最小带权子图

这个题差一点点就做出来了,思路是正确的,但是编码有一个小失误(忘记了优先队列元素的含义)

刚开始的思路是求src1和src2到dest的最短路的和,如果两个的最短路有重复就减去重复的。后来发现的例外:主要是因为减去的那个重复不一定是最大的,存在不是最短路的两个路径但是重复的成分很高,整体的和反而更小。

后来再思考了一下,那我不知道那个是重复路径的起点,不如我遍历一下,让每一个都当做起点。这样子的路径和就是dis[src1][k]+dis[src2][k]+dis[k][dest]
想到这里我觉得我找到了正确的思路,想要用一下Floyed去求最短路。一看节点个数1e5,然后就意识到肯定会超时。因为Floyed的复杂度是O(n^3)
那么只能进行优化,考虑正向建图求src1和src2到每个节点的距离,再反向建图求每个节点到dest的距离。因为数据量很大,所以要求不能使用简单的Dijkstra,要使用最小堆优化的Dijkstra,这样每次Djikstra的复杂度是O(nlogn),最后遍历一下的复杂度是O(n)。

但是在写Dijkstra的时候我是抄的板子,没有去理解优先队列节点的含义,最终导致出错了,也算是咎由自取吧。

吃了个饭回来又过了,泪目。

namespace D {/** 假如src1在src2到dest的路径上或者返过来,则是平凡的情况*/class Solution {using ll = long long;struct HeapNode {ll d;int u;HeapNode(ll d_, int u_):d(d_), u(u_){}bool operator <(const HeapNode&rhs) const {return d > rhs.d;}};public:long long minimumWeight(int n, vector<vector<int>>& edges, int src1, int src2, int dest) {vector<vector<pair<int, int>>> graph(n), reverse_graph(n);//建图int u, v, w;for (auto &edge : edges) {u = edge[0]; v = edge[1]; w = edge[2];graph[u].emplace_back(v, w);reverse_graph[v].emplace_back(u, w);}vector<ll> dis1(n), dis2(n), dis3(n);vector<bool> vis(n);auto dijkstra = [n, &vis](auto &&graph, auto &&dis, int s) {priority_queue<HeapNode> q;for (int i = 0; i < n; ++i) {dis[i] = LONG_LONG_MAX;}dis[s] = 0;for (int i = 0; i < n; ++i) vis[i] = false;q.emplace(0, s);while (!q.empty()) {HeapNode x = q.top(); q.pop();int u = x.u;if (vis[u]) continue;vis[u] = true;//print(u);auto &edges = graph[u];for (auto &pr : edges) {int v = pr.first;int w = pr.second;//print("\t", u ,v ,w);if (dis[v] > dis[u] + w) {dis[v] = dis[u] + w;q.emplace(dis[v], v);}}}};dijkstra(graph, dis1, src1);dijkstra(graph, dis2, src2);dijkstra(reverse_graph, dis3, dest);ll ans = LONG_LONG_MAX;for (int k = 0; k < n; ++k) {if (dis1[k] == LONG_LONG_MAX || dis2[k] == LONG_LONG_MAX || dis3[k] == LONG_LONG_MAX) {continue;}ans = min(ans, dis1[k] + dis2[k] + dis3[k]);}if (ans == LONG_LONG_MAX) return -1;else return ans;}};
}

经验总结

  • 重复的边对Dijkstra算法是没有影响的
  • Dijkstra算法需要的是最小堆,而默认的小于号得到的是最大堆,因此应该在重载小于号的时候让含义反过来。之所以会出现这样子是和堆的实际生成有关系(上游下游什么的,已经忘记了,有时间复习一下)
  • 为了避免初始化为正无穷的时候两个正无穷相加溢出,我们可以在相加前进行判断。
  • 需要注意Dijkstra对节点标记为已处理是在弹出堆顶元素进行的,而不是在入堆的时候进行的。这一点和一般的BFS不同。Dijkstra算法正确性主要是距离源节点最近的节点的最短路径已经确认
  • 可以放心大胆地用emplace,虽然不知道为什么有一次在emplace的时候报错了,当时心态很崩。

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

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

相关文章

Leetcode第286场周赛

绪论 上周因为有事没有参加周赛&#xff0c;这周没有错过。这次周赛拿到了人生第一个AK&#xff0c;参加大大小小的比赛这么多次&#xff0c;从来没有AK过&#xff0c;泪目了。 感觉这次比赛的思维难度对我来讲稍高一些&#xff0c;前三道题就花了一个小时&#xff0c;而以往…

第287场周赛

绪论 虽然是上周日参加的比赛&#xff0c;但是这周没有怎么学习&#xff0c;每天就是玩耍。也导致对周赛的总结迟迟没有进行。想着再拖下去下次周赛都要开始了&#xff0c;在这里补一下。 这场比赛总体比上场简单一些&#xff0c;但是最后一道题因为忘记初始化类内变量导致调试…

第288场周赛

绪论 虽然没有AK&#xff0c;但是不知道为什么排名比以前AK了都靠前。可能是因为最后一道题有些难度&#xff0c;缩小了我和大佬之间的差距。最后一个小时写最后一道题&#xff0c;累死累活想了一个贪心遍历的算法&#xff0c;当时是一直RE&#xff0c;后来下来调了调又WA了。 …

Clion远程部署和运行

绪论 作为Clion的忠实粉丝&#xff0c;现在的我的几乎所有的coding都是通过Clion完成。因为需要在服务器上进行开发&#xff0c;又离不开Clion&#xff0c;就了解了如何通过Clion远程部署和开发。 主要是借鉴了博客&#xff1a;使用Clion优雅的完全远程自动同步和远程调试c。如…

Ubuntu install ‘Bash to dock‘

绪论 在Ubuntu环境搭建这篇博客中记录了使用Dash To Dock来配置Ubuntu的菜单项&#xff0c;使得实现macOS一样的效果。为了配置新电脑的环境&#xff0c;我还是想安装这个软件。但是如今在Ubuntu Software中已经找不到这个软件了&#xff0c;我在网上借鉴了一些博客的经验才得…

Leetcode第309场周赛

Date: September 4, 2022 Difficulty: medium Rate by others: ⭐⭐⭐⭐ Time consuming: 1h30min 题目链接 竞赛 - 力扣 (LeetCode) 题目解析 2399. 检查相同字母间的距离 class Solution {public:bool checkDistances(string s, vector<int>& distance) {vec…

C++ 条件变量的使用

绪论 并发编程纷繁复杂&#xff0c;其中用于线程同步的主要工具——条件变量&#xff0c;虽然精悍&#xff0c;但是要想正确灵活的运用却并不容易。 对于条件变量的理解有三个难点&#xff1a; 为什么wait函数需要将解锁和阻塞、唤醒和上锁这两对操作编程原子的&#xff1f;为…

CentOS 7关闭firewalld启用iptables

在CentOS7中&#xff0c;有很多CentOS 6中的常用服务发生了变化。 其中iptables是其中比较大的一个。防火墙iptables被firewalld取代。 本文将介绍&#xff0c;如果采用systemctl关闭firewalld&#xff0c;开启iptables。 1.关闭firewalld [roothwcentos70-01 system]# systemc…

MP4文件格式的解析,以及MP4文件的分割算法

mp4应该算是一种比较复杂的媒体格式了&#xff0c;起源于QuickTime。以前研究的时候就花了一番的功夫&#xff0c;尤其是如何把它完美的融入到视频点播应用中&#xff0c;更是费尽了心思&#xff0c;主要问题是处理mp4文件庞大的“媒体头”。当然&#xff0c;流媒体点播也可以采…

MP4文件格式详解

一、基本概念 1.mp4概述 MP4文件中的所有数据都装在box&#xff08;QuickTime中为atom&#xff09;中&#xff0c;也就是说MP4文件由若干个box组成&#xff0c;每个box有类型和长度&#xff0c;可以将box理解为一个数据对象块。box中可以包含另一个box&#xff0c;这种box称为c…

H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

SkySeraph Apr 1st 2012 Email&#xff1a;skyseraph00163.com 一、MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二、MP4封装格式核心概念 1 MP4封装格式对应标准为 ISO/IEC 14496-12&#xff08;信息技术 视听对象编码的第12部分: ISO 基本媒体文件格式/Info…

Linux应用程序在内存中的地址布局

栈&#xff1a;局部变量&#xff08;初始化的和未初始化的&#xff0c;但不包含局部静态变量&#xff09;、局部只读变量&#xff08;const&#xff09;堆&#xff1a;动态分配的区域&#xff08;如使用malloc函数申请的区域&#xff09;BSS段&#xff1a;存储未初始化的全局变…

wpa_supplicant与wpa_cli之间通信过程

wpa_supplicant编译&#xff1a; 1. wpa_supplicant/Android.mk : -- wpa_cli -- wpa_supplicant -- libwpa_client.so 2. hostapd/Android.mk : -- hostapd_cli -- hostapd 从通信层次上划分&#xff0c;wpa_supplicant提供向上的控制接口 control interface&#xff0c;用于与…

关于c语言字符串函数和一些内存函数的的简介

关于c语言字符串函数和一些内存函数的的简介 求字符串长度的函数 strlen函数介绍![在这里插入图片描述](https://img-blog.csdnimg.cn/20190301142458376.jpg)注模拟实现 . [1 ]计数器方式 因为strlen 是求字符串长度的函数&#xff0c;所以不能改变字符串本身&#xff0c;所…

用结构体写一个简单的通讯录

一个简单的通讯录 通讯录应该具备简单的一些功能 1 增添联系人 2 删除联系人 3 查找联系人 4 修改联系人 5 按名字给联系人排序 6 查看通讯录 除此之外&#xff0c;应该在实现上还应该具备一些其他的功能函数 比如 初始化通讯录 这些都是功能函数&#xff0c;而整个函数入口应…

c动态内存管理

动态内存管理 我们之前要开辟内存用的方法都是定义变量&#xff0c;比如 但是上述开辟内存的方法有两个特点 1空间开辟大小是固定的 2数组在申明的时候&#xff0c;必须指定数组的长度&#xff0c;它所需要的内存在编译时分配 malloc和free c中提供一个动态内存开辟函数 这…

右移函数(字符串,数组)

右移函数 以上是数组右移&#xff0c;将int换成char 把数组内容改成字符串就行。

c中指针简介

c中指针简介 首先我们来看一下指针的一些基本概念 ![在这里插入图片描述](https://img 而对于指针的应用&#xff0c;平常有一些形式&#xff0c;总结了一下大概有这几种用法 对于以上的几种用法&#xff0c;我依次给出详尽的解释 //这是一个普通的整型变量 1 //首先从P 处开…

判断一个字符串是否另一个字符串的右移后的

首先我们把需要判断的字符串传进来&#xff0c;开辟一块大小为两个字符串的长度总和加1的动态的空间&#xff0c;然后后字符串拷贝函数将一个字符串拷贝到开辟空降中&#xff0c;再将这个字符串再次连接到这块动态的空间中&#xff0c;等于就是将一个字符串拷贝了两遍。然后比较…

不带头结点的链表基础操作(初始化,增删改查)

链表是什么&#xff1f; **链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。每个结点包括…