Leetcode第95场比赛回顾

栏目: 数据库 · 发布时间: 5年前

内容简介:这周五团队一起做了 Leetcode 第 95 场比赛。做到第二题,我就发现很多人可能到这里就不会了。做第三题时,我刚开始完全没想法,是先跳过去做第四题的,最后有想法了才把第三题干掉的。

零、背景

这周五团队一起做了 Leetcode 第 95 场比赛。

做到第二题,我就发现很多人可能到这里就不会了。

做第三题时,我刚开始完全没想法,是先跳过去做第四题的,最后有想法了才把第三题干掉的。

现在来看下比较有难度的一场比赛吧。

PS:这次比赛我是第一次直接在浏览器上做题的,没想到浏览器上敲代码这么方便。

正常比赛下来,只用了一点小时多一点。

明天又比赛了,我再尝试在浏览器上做题试试。

一、链表的中间结点

题号:876

题目:Middle of the Linked List

题意:输出链表的中位数。 如果有两个(偶数长度),输出后面那个。

思路:最简单的方法就是先循环求出链表的长度,计算出答案的位置,然后循环找到那个位置即可。

可以看到,这样需要循环两次才能找到答案。

另一种更快的方法是使用快慢指针,这样循环一遍就可以找到答案了。

二、石子游戏

题号:877

题目:Stone Game

题意:N堆石头排成一行, AlexLee 两个人轮流拿走一堆石头。

问最终第一个人 Alex 拿到的石头是否可以比第二个多。

规则:有偶数堆石头,每次只能从两头来选一堆。

思路:第一眼看到这道题,我们可以确定这是一道博弈题。

但是不能直接根据递归的子状态来判断是否能赢。

我们只能做到求出子状态的最优值,返回给当前状态,然后求出当前状态的最优值。

p[1] p[2]... p[n-1] p[n] 为例。

当前状态是 1~nAlex 的目标是在 1~n 的两边选择一堆石头,使得自己的总石头数量最大,我们称为 f(1,n)

Alex 选择 p[1] 时, Lee 肯定会尽使自己的石头数最大,即 f(2,n)

此时 Alex 的石头总数是 sum(1,n) - f(2,n)

Alex 选择 p[n] 时, Lee 的选择则是 f(1,n-1)

此时 Alex 的石头总数是 sum(1,n) - f(1,n-1)

面对这两种选择, Alex 肯定选择两个结果里最大的选择。

分析到这里,我们也就把这个博弈过程讲清楚了。

具体用代码实现就是一个 DFS

而考虑到子状态存在重复计算,则需要记忆状态。

当然,这两个结合起来,其实就是动态规划了。

Leetcode第95场比赛回顾

赛后,大家讨论的时候,一个同学说:我没找到 Alex 失败的情况,于是直接提交 Alex 永远成功,想看看反例是什么。结果提交后这道题就过了。

然后也有几个同学说自己的算法敲错了,最终也都过了。

那为什么会这样呢?

后来我想了想,想明白了为什么 Alex 必胜 Lee 必败。

而且道理也很简单,不信你看。

总共有偶数堆石头,石头总个数是奇数个。

这说明最终肯定有一个人胜出。

偶数堆按奇偶性分别求和,则要么偶数堆大,要么奇数堆大。

假设石头堆是 1 ~ 2n

如果偶数堆大,则 Alex 选择 p[2n] 这堆石头, Lee 只能选择 p[1]p[2n-1] ,即只能选择奇数堆。

之后 Alex 依旧是选择偶数堆,而 Lee 只能选择奇数堆。

最终, Alex 选择的都是偶数堆, Lee 选择的都是奇数堆,这样 Alex 就比 Lee 选的多了。

而对于奇数堆大,是一个道理。

所以第一个选择的人 Alex 必胜了。

这道题算是有史以来代码最短的题了,只需要 return true; 即可。

三、第 N 个神奇数字

题号:878

题目:Nth Magical Number

题意:如果正整数可以被 A 或 B 整除,那么它是神奇的。 返回第 N 个神奇数字。

规则:由于答案可能非常大,返回它模 10^9 + 7 的结果。

思路:看到这道题的第一眼,我是一脸懵逼的,于是就先做下一道题了。

下一道题做完后,只剩这一道题了,就只能分析这道题的特征了。

一分析不要紧,还真找到一个规律:神奇数是有周期的,周期就是 A和B的最小公倍数。

假设 A 和 B 的最小公倍数是 G,其中有 m 个神奇数,分别表示为 f[1],f[2]...f[m]

则第 m+1 个神奇数肯定是 G + f[1] ,而第 m + 2 个神奇数肯定是 G + f[1]

推广就是,第 N 个神奇数是 G * (N/m) + f[N%m]

那接下来的问题就是:怎么求最小公倍数以内的所有神奇数?会不会很多?会不会超时?

面对发自内心的三连问,我想先解决第一个问题:先写出代码提交了再说。

写了一个循环就求出了所有的神奇数,提交后就过了。

Leetcode第95场比赛回顾

然后我思考:为什么没超时?会不会本来就不多?怎么证明?

面对接下来的三连问,其实是一个问题:怎么证明公倍数内的神奇数不多。

简单一思考,发现很容易证明。

与 A 有关的神奇数是 A,2A,...,BA

与 B 有关的神奇数是 B,2B,...,AB

这样合起来神奇数最多就是 A+B-1 个。

在考虑公约数的问题,神奇数还会比这个还少,即只有 G/A + G/B - 1 个。

而 A 和 B 只有几万,复杂度可以接受,所以这样做不会超时,证闭。

四、盈利计划

题号:879

题目:Profitable Schemes

题意:有 G 个人,有多起犯罪同时发生。

每个犯罪需要 group[i] 个人,可以获取 profit[i] 的利润。

统计到犯罪至少获取的利润是 P,问可能有哪些犯罪发生。

思路:只要题意看懂,就可以看出这是一道基本的动态规划题,甚至是背包问题的变种。

直接把涉及到的变量组装起来,就可以表达出状态: f(G, P, n)

含义是前 n 起犯罪里不超过 G 人时至少获得利润 P 的情况数。

此时对第 n 起犯罪分情况讨论。

如果参与犯罪(前提是能),则状态转化为 f(G-g[n], P-p[i], n-1) + check(p-p[i])

check 的含义是到目前未知,利润是否已经够了,够了就算一个答案。

如果不参与犯罪,则状态是 f(G, P, n-1)

就这样,就可以求出答案来,复杂度 O(n^3)

Leetcode第95场比赛回顾

五、最后

这次比赛其实蛮有难度的。

除了第一题是水题,第二第四是动态规划,第三是数学题,一般人面对这三道题都会是一道坎。

除非你非常聪明,一般人都需要大量的训练才能熟练的掌握这些题型的。

当然,第二题其实不好,很多人代码敲错了都水过去了。刚才我看了下我的代码,有个地方敲错了,少了个逗号,也过了。

PS:最近我在想怎么把自己做过的题组织起来,以供大家搜索、分类,从而方便的进行专项练习。

目前的选择有两种,一种是在我的网站上实现这个功能,一种是使用知识星球的标签功能,大家怎么看这个呢?

-EOF-


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python源码剖析

Python源码剖析

陈儒 / 电子工业出版社 / 2008-6 / 69.80元

作为主流的动态语言,Python不仅简单易学、移植性好,而且拥有强大丰富的库的支持。此外,Python强大的可扩展性,让开发人员既可以非常容易地利用C/C++编写Python的扩展模块,还能将Python嵌入到C/C++程序中,为自己的系统添加动态扩展和动态编程的能力。. 为了更好地利用Python语言,无论是使用Python语言本身,还是将Python与C/C++交互使用,深刻理解Pyth......一起来看看 《Python源码剖析》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

html转js在线工具
html转js在线工具

html转js在线工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具