Press "Enter" to skip to content

Huahua's Tech Road

花花酱 LeetCode 403. Frog Jump

肯定是用DP,但我自己想了一个奇怪的方法,勉强过了…

使用dp[i] = {steps},表示可以达到stones[i]的最后一跳的unit的集合。
dp[0] = {0}
dp[1] = {1} if stones[1] = 1 else {}
然后对于stones[i],枚举所有step – 1, step, step + 1三种情况,看看是否可以跳到新的石头上面(使用一个hashtable判断),如果可以的吧,把跳的unit存到dp[j]中。相当于推了。
需要使用hashset去重,不然会超时。

时间复杂度:O(n2)
空间复杂度:O(n2)

“优化”:由于每次只能k-1,k,k+1steps,所以最大的units和n是线性关系,达到stones[i]最多跳i+1个units。
可以用二维数组dp[j][k] := 是否可以通过k步跳到stones[j].
dp[j][k] = dp[i][k-1] || dp[i][k] || dp[i][k+1], k = stones[j] – stones[i]. 即从stones[i]跳到stones[j],并且要求跳到stones[i]的可能步数中存在k-1,k,k+1。
时间复杂度和空间复杂度是一样的。

花花酱 LeetCode 430. Flatten a Multilevel Doubly Linked List

用递归实现比较简单一点。如果需要完美的one pass则需要写一个helper function,返回flattern后的head和tail.

注意这是双向链表,要把A把B连接到一起,需要同时改两个指针A->next = B, B->prev = A。

时间复杂度:O(n)
空间复杂度:O(n) / stack

花花酱 LeetCode 368. Largest Divisible Subset

也算是一道比较经典的DP题了,需要找到一个最大的子集,使得其中元素两两的余数为0。

我们假设有一个集合为{a1, a2, a3, …, an}, {a1 < a2 < … < an)

如果 a2 % a1 = 0, a3 % a2 == 0, 那么a3 % a1 一定也等于0。也就是说a2是a1的倍数,a3是a2的倍数,那么a3一定也是a1的倍数。所以我们并不需要测试任意两个元素之间的余数为0,我们只需要检测a[i]是否为a[i-1]的倍数即可,如果成立,则可以确保a[i]也是a[i-2], a[i-3], … a[1]的倍数。这样就可以大大降低问题的复杂度。

接下来就需要dp就发挥威力了。我们将原数组排序,用dp[i]来表示以a[i]结尾(集合中的最大值),能够构建的子集的最大长度。

转移方程:dp[j] = max(dp[j], dp[i] + 1) if nums[j] % nums[i] = 0.

这表示,如果nums[j] 是 nums[i]的倍数,那么我们可以把nums[j]加入以nums[i]结尾的最大子集中,构建一个新的最大子集,长度+1。当然对于j,可能有好多个满足条件的i,我们需要找一个最大的。

举个例子:
nums = {2, 3, 4, 12}
以3结尾的最大子集{3},长度为1。由于12%3==0,那么我们可以把12追加到{3} 中,构成{3,12}。
以4结尾的最大子集是{2,4},长度为2。由于12%4==0,那么我们可以把12追加到{2,4} 中,构成{2,4,12} 。得到最优解。

这样我们只需要双重循环,枚举i,再枚举j (0 <= i < j)。时间复杂度:O(n^2)。空间复杂度:O(n)。

最后需要输出一个最大子集,如果不记录递推过程,则需要稍微判断一下。

花花酱 LeetCode 2296 Design a Text Editor

方法1:双向链表来存储文本,迭代器指向光标所在的位置。加一个dummy head会使代码简单很多。

时间复杂度:TextEditor O(1) addText O(|text|) deleteText O(k) cursorLeft O(k) cursorRight(k)
空间复杂度:O(n)

由于每个字符需要创建一个节点(17+个字节),虽然没有超时,但实际工程中是不能使用这种方式的。

方法2: 用两个string来代表光标左边的字符串和光标右边的字符串。注:右边字符串是反转的。

左右两边的字符串只会增长(或者覆盖),不会缩短,这是用空间换时间。

删除的时候就是修改了长度而已,并没有缩短字符串,所以是O(1)的。
如果缩短的话需则要O(k)时间,还要加上内存释放/再分配的时间,应该会慢一些但不多。

移动光标的时候,就是把左边字符串的最后k个copy到右边的最后面,或者反过来。同样没有缩短,只会变长。

时间复杂度: TextEditor O(1) addText O(|text|) deleteText O(1) cursorLeft O(k) cursorRight(k)
空间复杂度:O(n),n为构建的最长的字符串

花花酱 LeetCode 3498 Reverse Degree of a String

送分题,简单仿真即可。

时间复杂度:O(n)
空间复杂度:O(1)