Leetcode第286场周赛

绪论

上周因为有事没有参加周赛,这周没有错过。这次周赛拿到了人生第一个AK,参加大大小小的比赛这么多次,从来没有AK过,泪目了。
在这里插入图片描述
感觉这次比赛的思维难度对我来讲稍高一些,前三道题就花了一个小时,而以往只需要半个小时。
看了一下排名前面的大牛们,还是十分钟就AK了,深觉自己还马达马达大内。

题目分析

比赛链接:https://leetcode-cn.com/contest/weekly-contest-286/

题目难度上第二题和第三题都有一些思维量,不像以前直接模拟。第四题我直接记忆化搜索在最后一分钟过了,当时学习动态规划的时候接触到记忆化搜索对其嗤之以鼻,觉得就是弱者想不出来状态转移方程,用这种近似暴力的方式来处理。然后现在发现,弱者竟是我自己,记忆化搜索真香。

A:找出两数组的不同

签到题,数据量很小,也没有仔细想直接两个哈希集合,去重并判断每个元素是否在另一个集合出现过,没有出现过就添加到结果数组中。

class Solution {
public:vector<vector<int>> findDifference(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> s1, s2;for (auto x : nums1) s1.insert(x);for (auto x : nums2) s2.insert(x);vector<vector<int>> ret(2);for (auto x : s1) {if (s2.count(x) == 0) ret[0].push_back(x);}for (auto x : s2) {if (s1.count(x) == 0) ret[1].push_back(x);}return ret;}
};

B:美化数组的最少删除数

题目的意思就是偶数位置的元素要和下一个位置的元素不相等。因为只向后看, 所以当时想到了一个构造答案的方法:首先统计每个数字连续出现的次数x。对于偶数位置,ans+=x-1,对于奇数位置,ans+=x-2。最后如果要填充奇数位置,则++ans,因为最后一个位置必须要保证数组的长度为偶数。

class Solution {
public:int minDeletion(vector<int>& nums) {vector<pair<int, int>> cnt;int n = nums.size();for (int i = 0; i < n; ) {int j = i + 1;while (j < n && nums[j] == nums[i]) ++j;cnt.emplace_back(nums[i], j - i);i = j;}n = cnt.size();int ans = 0, x;bool is_even = true;for (int i = 0; i < n; ++i) {x = cnt[i].second;if (is_even) {ans += x - 1;is_even = false;} else {if (x == 1) {is_even = true;} else {ans += x - 2;}}}if (!is_even) ++ans;return ans;}
};

这样做的正确性在于,对于偶数位置,他如果连续出现了多次,最多只能保留1个。对于奇数位置,如果连续出现了多次,最多只能保留2个。这里我们每次都选择的是尽可能保留以满足题目中的最短长度。最后我们处理了一下让整个数组的长度为偶数:如果下一次要填充的是奇数位置的数字,那么说明前面的位置是偶数位置,需要将其删除。

接下来我们简单讨论一下为什么尽可能保留数字是最优的。假如某个位置我们可以保留某个数字但是我们将其删光了,后面的数字会移动到前面,同样需要删除,并不能让解更好。详细的证明需要分类讨论之类的,这里我们就不求甚解了。

C:找到指定长度的回文数

是一个对我来讲有点思维量的模拟,我们需要能够构造任意长度,第任意大小的回文串。为了能够构造第x大的回文串,我们需要使用类似进制转换的思想。
对于相同长度的回文串,其值和相对大小是由前面一半的数字支配的,后面一半的数字都不用进行考虑。
第一个数字只能是1-9,后面的数字每一位都可以是0-9。对于一个回文串长度为intLength,他的所有可能结果是maxn=9∗10intLength−12maxn = 9*10^{\frac{intLength -1}{2}}maxn=9102intLength1。如果x大于maxn,则直接返回-1。
接下来我们来从前往后确定每一位数字的大小。第一位数字确定后,后面的数字有maxn/=9种可能。即第1——maxn个回文串的第一位是1,第maxn+1——2maxn个回文串的第一位是2。为了确定第一位的数字,我们可能想要让x/maxn来确定。但是整除需要我们特别处理一下。
因为算数运算默认是从0开始的,0——maxn-1 /x都是0。为了寻求这种统一,我们不妨给x减一,从而可以直接套用算术运算。
对于后面的位数也是同样的道理。总结一下就是为了能够让x对固定步长(上面的maxn)进行分组,我们让x-1,从而将原本1——maxn变成了0——manx-1,变成了在数值意义上的同一组。
后面取余仍然会从0开始,所以我们只用减一一次。

class Solution {using ll = long long;ll n_, maxn_, len_;ll work(ll x) {--x;vector<int> arr;ll n = n_;arr.push_back(x / n + 1);x %= n;ll len = len_;len -= 2;while (len > 0) {n /= 10;arr.push_back(x / n);x %= n;len -= 2;}ll ret = 0;for (auto x : arr) ret = ret * 10 + x;if (len_ & 1) arr.pop_back();int nn = arr.size();for (int i = nn - 1; i >= 0; --i) ret = ret * 10 + arr[i];return ret;}public:vector<long long> kthPalindrome(vector<int>& queries, int intLength) {len_ = intLength;int n = (intLength - 1) >> 1;n_ = 1;for (int i = 0; i < n; ++i) {n_ *= 10;}maxn_ = n_ * 9;vector<ll> ret;for (auto x : queries) {if (x > maxn_) ret.push_back(-1);else {ret.push_back(work(x));}}return ret;}};

仔细研究了一下大牛的解法,发现我这里处理复杂的原因是没有想到每位填充的也是十进制数字,那么x-1+maxn就是前一半数字。x-1是第一位从0开始的第x个数字,加上maxn就是第一位从1开始的。

D:从栈中取出 K 个硬币的最大面值和

我们很容易就可以计算出从一个栈中取m个硬币的面值和,那么问题就是我们可以从n个栈中取硬币,每个栈可以取0个或多个,最终取k个的最大和。想了一下也没有什么状态转移的,就直接记忆化搜索了。

class Solution {int n_;vector<vector<int>> sum;vector<int> cnt;vector<vector<int>> memo;int dfs(int x, int k) {if (x == n_) {return sum[x][k];} else {if (memo[x][k] != -1) return memo[x][k];int kk = std::min(k, (int)sum[x].size() - 1);for (int i = std::max(0, k - cnt[x]); i <= kk; ++i) {memo[x][k] = max(memo[x][k], sum[x][i] + dfs(x + 1, k - i));}}return memo[x][k] == -1 ? INT_MIN : memo[x][k];}
public:int maxValueOfCoins(vector<vector<int>>& piles, int k) {int n = piles.size();memo.resize(n, vector<int>(k + 1, -1));n_ = n - 1;sum.resize(n);cnt.resize(n);for (int i = 0; i < n; ++i) {auto &arr = piles[i];auto &s = sum[i];s.push_back(0);for (auto x : arr) {s.push_back(s.back() + x);}}int t = 0;for (int i = n - 1; i >= 0; --i) {cnt[i] = t;t += piles[i].size();}return dfs(0, k);}
};

当时最后几分钟写完后一直运行错误,我心态有点崩,觉得果然又要到此为止了吗。但是还是耐下性子去看代码到底哪里有问题。当时报的是堆上的错误,我就觉得是不是哪里数组越界了。认真一看,sum、cnt不可能越界,那是不是备忘录memo越界了呢?仔细一想,memo的第二个维度是可以取到k的,而我第二个维度的大小只有k,于是将第二个维度的大小改成k+1就过了。
以前写记忆化搜索都是自己特化一个对pair的哈希然后用unordered_map做,这次因为时间不够用的二维数组,而之前都没有写过用二维数组进行备忘录,所以就没注意过这个问题。

虽然时间紧迫,但是我对自己这个记忆化搜索还是挺满意的,有备忘录,有必要的剪枝,代码也很紧凑。
首先初始化了一下memo和sum数组,sum[x][k]表示的是第x个栈取k个硬币的面值和,memo[x][k]表示的是对于从x到n-1的栈,总共取k个硬币的最大面值和,最终的答案就是memo[0][k],初始化为-1表示没有进行更新,如果memo[x][k]不可能存在,则赋值为无穷小。因为我们求的是最大值,所以不会用到这个状态。

cnt数组是为了剪枝维护的状态,cnt[x]表示从x+1到n-1总共有多少个硬币,std::max(0,k-cnt[x])就表示第x个栈至少要取多少枚硬币才能够保证从x到n-1能够取到k个硬币,std::min(k, (int)sum[x].size()-1)表示第x个栈至多能够取到多少个硬币。

总共最多有O(x)*O(k)=2e6个状态,每个状态至多求解一次,每个状态的求解至多是O(k),因此最坏的时间复杂度是2e9。本来心里有些打鼓,但是提交后发现通过了,非常开心。

仔细阅读了一下大牛的解法,发现是一个01背包问题。感觉自己对背包问题的理解还是不够深刻,应该专门再整理一下背包问题的思路。

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

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

相关文章

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

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

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