第287场周赛

绪论

在这里插入图片描述
虽然是上周日参加的比赛,但是这周没有怎么学习,每天就是玩耍。也导致对周赛的总结迟迟没有进行。想着再拖下去下次周赛都要开始了,在这里补一下。
这场比赛总体比上场简单一些,但是最后一道题因为忘记初始化类内变量导致调试好久,血泪教训。

题目分析

A:转化时间需要的最少操作数

因为单独考虑小时、分钟太过繁琐,我的方法是将其转换成时间戳(类似chrono的time_since_epoch方法)。

class Solution {
public:int convertTime(string current, string correct) {int h1 = (current[0] - '0') * 10 + current[1] - '0';int h2 = (correct[0] - '0') * 10 + correct[1] - '0';int m1 = (current[3] - '0') * 10 + current[4] - '0';int m2 = (correct[3] - '0') * 10 + correct[4] - '0';int x1 = h1 * 60 + m1;int x2 = h2 * 60 + m2;if (x1 > x2) x2 += 24 * 60;int x = x2 - x1;int ans = 0;ans += x / 60;x %= 60;ans += x / 15;x %= 15;ans += x / 5;x %= 5;ans += x / 1;x %= 1;return ans;}
};

B:找出输掉零场或一场比赛的玩家

map去存储每个节点的入度,之所以用map是因为要求结果有序。
需要注意的一点是即使是赢家我们也应该更新这个信息,因为我们得统计入度为0的节点。

class Solution {
public:vector<vector<int>> findWinners(vector<vector<int>>& matches) {map<int, int> score;int x, y;for (auto &arr : matches) {x = arr[0]; y = arr[1];score[x] += 0;score[y] += 1;}vector<vector<int>> ans(2);auto &ans0 = ans[0];auto &ans1 = ans[1];for (auto &pr : score) {if (pr.second == 0) ans0.push_back(pr.first);else if (pr.second == 1) ans1.push_back(pr.first);}return ans;}
};

C:每个小孩最多能分到多少糖果

这个题目很关键的一点就是每个小孩拿到的糖果数目是相同的,如果没有抓住这一点可能无从下手。如果确定每个小孩拿到的糖果数x,那么每堆可以分的孩子数目是确定的。我们可以将其转换成一个判定问题:对于x,可以分给f(x)个孩子,f(x)是否大于等于k。每次判定的复杂度是O(n)的。
很容易发现,f(x)是单调递减的。因此我们可以考虑使用二分。
需要注意糖果数目可能超过了整数范围。

class Solution {
public:int maximumCandies(vector<int>& candies, long long k) {using ll = long long;ll r = 0;for (auto x : candies) r += x;if (r < k) return 0;auto check = [&](ll t) -> bool {ll sum = 0;for (auto x : candies) sum += x / t;return sum >= k;};ll l = 1, mid;ll ans = 1;while (l <= r) {mid = l + (r - l) / 2;if (check(mid)) {ans = mid;l = mid + 1;} else {r = mid - 1;}}return ans;}
};

D:加密解密字符串

最后一道题有一点意思,刚开始一看,这不就是一个简单的模拟吗?对于编码没什么说的,这么小的数据闭着眼睛都过了。对于解码却有一些讲究。当时我看着200的数据有点上头,觉得这还有什么好考虑的,直接模,结果果然超时了。。。
开始思考为什么会超时。因为values中可能出现重复的字符串,所有一个位置可能有不同的字符。假如values中每个字符串都是一样的,而需要解码的字符串就是这些一样的字符串组成的,那么每个位置都有很多种组合,很容易就超过1e9了。
虽然组合有可能超过1e9,但是实际的dictionary却很小,所以我们必须对组合进行剪枝,而且必须在前缀阶段就进行剪枝,如果等到解码结束再进行剪枝已经迟了。(我刚开始模拟就没有剪枝)
如果我们直接用数据对比前缀,每次的时间复杂度都是O(200)左右,虽然貌似不大,但是也会超时。
为了更好的进行 剪枝,我们就必须高效地判断一个前缀是否出现在dictionary。和前缀相关的操作容易联想到字典树。
字典树虽然名字听起来很高大上,但是实际上是一个非常容易理解的数据结构,每个节点存储一个字符,有26个子孩子,用来记录在这个字符后是否有其他字符。还需要一个布尔变量用来记录当前字符是否可以作为某个单词的结尾。
因为我们的字典树只进行添加,不会删除,所以可以使用内存池进行优化。如果直接使用new在堆上分配内存,那么每次添加新节点都需要new一次,最后程序结束还需要delete。这对内存的管理提出了要求。如果我们使用简易的内存池就可以避免这个问题。具体的讲,就是用vector管理内存。vector有自动扩容机制,并且不用担心内存泄漏。
每个节点使用下标作为指针指向下一个节点。

struct Trie {struct Node {char c_;bool is_word_;vector<int> next_;Node(char c): next_(26, -1), is_word_(false) {}};int root_ = 0;vector<Node> nodes_;public:Trie() {nodes_.emplace_back(' ');}void add(const string &s) {int root = root_, t;for (auto c : s) {int t = nodes_[root].next_[c - 'a'];if (t == -1) {//节点不存在nodes_.emplace_back(c);t = nodes_[root].next_[c - 'a'] = nodes_.size() - 1;}root = t;}nodes_[root].is_word_ = true;}};

上面的字典树没有实现search方法匹配前缀。因为在实际搜索的过程中,我们是一个字母一个字母进行确认,所以可以将前缀匹配和搜索结合起来,这样子我们在搜索下一个字符的时候只搜索在字典树的字符,优化算法。

class Encrypter {struct Trie {struct Node {char c_;bool is_word_;vector<int> next_;Node(char c): next_(26, -1), is_word_(false) {}};int root_ = 0;vector<Node> nodes_;public:Trie() {nodes_.emplace_back(' ');}void add(const string &s) {int root = root_, t;for (auto c : s) {int t = nodes_[root].next_[c - 'a'];if (t == -1) {//节点不存在nodes_.emplace_back(c);t = nodes_[root].next_[c - 'a'] = nodes_.size() - 1;}root = t;}nodes_[root].is_word_ = true;}};vector<char> keys_;vector<string> values_;Trie trie_;unordered_map<char, int> keys_map_;unordered_map<string, vector<int>> values_map_;vector<vector<int>> init(const string &s) {vector<vector<int>> ans;int n = s.size();for (int i = 0; i < n; i += 2) {ans.emplace_back();auto &arr =ans.back();auto &t = values_map_[s.substr(i, 2)];for (auto x : t) {arr.push_back(keys_[x] - 'a');}}return ans;}
public:Encrypter(vector<char>& keys, vector<string>& values, vector<string>& dictionary): keys_(keys), values_(values){for (auto &s : dictionary) {trie_.add(s);}int n = keys.size();for (int i = 0; i < n; ++i) {keys_map_[keys[i]] = i;}n = values.size();for (int i = 0; i < n; ++i) {values_map_[values[i]].push_back(i);}}string encrypt(string word1) {string ans;for (auto c : word1) {ans.append(values_[keys_map_[c]]);}return ans;}int decrypt(string word2) {auto arr = init(word2);int n = arr.size();int ans = 0;function<void(int, int)> dfs;dfs = [&](int idx, int root) {if (idx == n) {if (trie_.nodes_[root].is_word_) ++ans;return;}auto &vec = arr[idx];int t;for (auto x : vec) {t = trie_.nodes_[root].next_[x];if (t == -1) continue;dfs(idx + 1, t);}};dfs(0, 0);return ans;}
};

但是在实现字典树的过程中我忘记对Node的is_word_字段进行初始化,导致出错。幸亏最终调试出来了。

经验总结

这次周赛偏简单,题目思维量不是很大,虽然有一些编码量。前三道题里就是第三道的二分比较需要一些思考。第四道题需要考虑到使用字典树进行前缀匹配。

虽然是第一次实现字典树,出现了一个bug,但是总体还是比较满意的。代码紧凑,逻辑完整。

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

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

相关文章

第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;结点可以在运行时动态生成。每个结点包括…

链表面试题1:反转单链表,不带头结点。

三个指针p1,p2,p3&#xff0c;p1指向头结点的前一个结点&#xff0c;也就时指空&#xff0c;p2指向头结点&#xff0c;p3指向头结点下一个结点。 p3指向p2的下一个&#xff0c;让p2指针域指向p1&#xff0c;让p1挪到p2上&#xff0c;再让p2指向p3.

链表面试题2:编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

我们可以&#xff0c;用两个新链表&#xff0c;一个存比基准值大的&#xff0c;另一个存比基准值小的。然后再拼接在一起。 用尾插的方法&#xff0c;首先说小的&#xff0c;创建两个指针&#xff0c;一个头&#xff0c;一个尾&#xff0c;再创建个指针跑链表&#xff0c;扫描…