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。如…

C++ 单例模式 call_once : terminate called after throwing an instance of ‘std::system_error‘

在学习了C中可以使用call_once进行初始化资源后&#xff0c;我就想着写一个单例模板供以后使用。 template<typename T> class SingleTon {using Ptr std::shared_ptr<T>;static Ptr p;static std::once_flag flag;template<typename ...Args>static void …

C++读写锁造成死锁

C14支持std::shared_timed_mutex C17支持std::shared_mutex 前者相比后者支持的操作更多&#xff0c;但是后者相对性能更好。 使用std::lock_guard<std::shared_mutex>和std::unique_lock<std::shared_mutex>互斥访问使用std::shared_lock<std::shared_mutex…

每日一题:449. 序列化和反序列化二叉搜索树

题目分析 题目链接&#xff1a;449. 序列化和反序列化二叉搜索树 觉得序列化很简单&#xff0c;前序遍历、后序遍历、中序遍历、层序遍历等等。其中得到前序遍历和后序遍历是可以通过递归解法反序列化的&#xff0c;觉得这样子做有点复杂。就想着可不可以一次遍历。一次遍历的…

C++高效集合数据结构设计

绪论 在复杂算法实现过程中我们经常会需要一个高效的集合数据结构&#xff0c;支持常数级别的增、删、查&#xff0c;以及随机返回、遍历&#xff0c;最好还能够支持交集、并集、子集操作 哈希集合实现 大家可能很快想到unordered_set&#xff0c;unordered_set由于底层是哈…

C++ 工具函数库

在写一些大型项目的过程中经常需要一些工具函数&#xff0c;例如获取随机数、计时器、打印函数、重要常量&#xff08;如最大值&#xff09;、信号与槽等&#xff0c;由于每一个工程都自己手动实现一个实在是太傻&#xff0c;我将其总结放入一个文件中。 utils.h // Copyright…

muduo网络库使用入门

muduo网络库介绍 muduo网络库是陈硕大神开发的基于主从Reactor模式的&#xff0c;事件驱动的高性能网络库。 网络编程中有很多是事务性的工作&#xff0c;使用muduo网络库&#xff0c;用户只需要填上关键的业务逻辑代码&#xff0c;并将回调注册到框架中&#xff0c;就可以实…

C++ map/unordered_map元素类型std::pair<const key_type, mapped_type>陷阱

在开发的过程中需要遍历一个unordered_map然后把他的迭代器传给另一个对象&#xff1a; class A; class B { public:void deal(const std::pair<int, A>& item); }; std::unordered_map<int, A> mp; B b; for (auto &pr : mp) {b.deal(pr); }在我的项目中…

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++ 模板函数、模板类:如果没有被使用就不会被实例化

C中如果一个模板函数没有使用过&#xff0c;那么其局部静态变量都不会被实例化&#xff1a; class A { public:A() {edward::print("A ctor");} };template<typename T> void test() {static A a; }int main() {test<int>(); //如果注释掉则不会有输出r…

C++ 条件变量的使用

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

C++Primer学习笔记:第1章 开始

本博客为阅读《C Primer》&#xff08;第5版&#xff09;的读书笔记 ps:刚开始的时候我将所有的笔记都放在一篇博客中&#xff0c;等看到第六章的时候发现实在是太多了&#xff0c;导致我自己都不想看&#xff0c;为了日后回顾&#xff08;不那么有心理压力&#xff09;&#…

【ubuntu】ubuntu14.04上安装搜狗输入法

** 在ubuntu14.04.4 desktop 64amd版本上安装sogou输入法 ** 0.换安装源为中国源&#xff08;可选&#xff0c;下载会快些&#xff09; 1.搭fcitx环境 2.安装sogou for linux 详细步骤&#xff1a; 因为sogou中文输入法基于fcitx(Free Chinese Input Toy for X),需要先搭环境…

【ubuntu】ubuntu下用make编译程序报错找不到openssl/conf.h

ubuntu下用make编译程序报错找不到openssl/conf.h 安装libssl-dev:i386&#xff0c;sudo apt-get install libssl-dev:i386 看好版本&#xff0c;如果不加i386默认下载的是32位&#xff0c;用ln命令连接过去也还是用不了的!libssl.dev安装好后&#xff0c;用find / -name libs…

【ubuntu】ubuntu如何改变系统用户名

ubuntu如何改变系统用户名 方法1&#xff1a;修改现有用户名 方法2&#xff1a;创建新用户&#xff0c;删掉旧用户 方法1&#xff1a; * *—&#xff01;&#xff01;&#xff01;有博客说要先改密码&#xff0c;再改用户名&#xff0c;否则会出现无法登陆状况&#xff01;&…

什么是signal(SIGCHLD, SIG_IGN)函数

什么是signal(SIGCHLD, SIG_IGN)函数 在进行网络编程时候遇到这个函数的使用&#xff0c;自己学习结果如下&#xff0c;有不对请帮忙指正:) signal(SIGCHLD, SIG_IGN)打开manpage康一康~ sighandler_t signal ( int signum, sighandler_t handler );参数1 int signum: 就是…

ssh连接不上linux虚拟机

ssh连接不上linux虚拟机 1.开启ssh服务 linux虚拟机下命令行输入&#xff1a; start service ssh如果显示没有ssh&#xff0c;就下面两个试一试哪一个ok&#xff0c;安装一下ssh&#xff1a; sudo apt-get install openssh-server sudo apt-get install sshd2.还有人说可能是…