代码随想录:额外题目
数组
有多少小于当前数字的数字
有效的山脉数组
独一无二的出现次数
移动零
旋转数组
寻找数组的中心下标
在排序数组中查找元素的第一个和最后一个位置
按奇偶排序数组II
搜索插入位置
链表
两两交换链表中的节点
回文链表
重排链表
|
|
快慢指针,slow 和 fast,让 slow 指向链表最中间的位置,然后将链表的后半部分反转。 pre 为后面链表的头结点,两个指针,一个指向第 1 个链表,一个指向第 2 个链表,合并两个链表。
|
|
环形链表
哈希表
同构字符串
查找常用字符
|
|
|
|
字符串
长按键入
本题较为复杂,建议多加练习。
|
|
本题在自己做时,最先想到的就是:判断 name 是否是 typed 的子序列。
但这样写存在一个漏洞,如:name=“alex”,typed=“aaleexa”,出现非长按键入的字符无法判断。
这种写法的代码如下:
|
|
为了不出现上面的问题,自己写了很久,怎么都不正确。
参考了答案,使用双指针来实现,这样双指针的处理还是比较巧妙的。
双指针:i 和 j。
-
如果 name[i] 和 typed[j] 相等,则同时将 i 和 j 加 1。
-
否则,如果 typed[j-1]==typed[j],则说明 j 位置是前面字符的重复键入,只将 j 加 1。
-
如果上面两种情况都不满足,直接返回 false。
最后,如果 i 等于 len(name),说明 name 字符串的每一个位置都参与了比较,返回 true。
|
|
比较含退格的字符串
二叉树
求根节点到叶节点数字之和
将二叉搜索树变平衡
相同的树
填充每个节点的下一个右侧节点指针
N皇后II
贪心
Dota2参议院
本题较难,建议多加理解和练习。
|
|
自己写了很久都有问题,参考代码随想录,使用贪心算法。
贪心的策略是:尽量禁止自己后面的对手。
因为前面的对手已经使用过权利了,而后续的对手依然可以使用权利消灭自己的同伴。
使用 R 和 D 标记现存的数组中是否还有 R 和 D,如果不能同时满足 R&&D,则退出循环。
使用一个变量 flag 用于跟踪 R 和 D 之间的“优势”。如果 flag 为正,则 Radiant 在前;如果为负,则 Dire 在前。
遍历 senate,如果遇到的是 R,如果 flag<0,则消灭 R(置为 0),否则,R 标记为 true(数组中还有 R),最后将 flag++。
如果遇到的是 D,如果 flag>0,则消灭 D(置为 0),否则 D 标记为 true(数组中还有 D),最后将 flag–。
最后,R 和 D 变量只有一个为 true,返回对应的字符串即可。
|
|
分割平衡字符串
动态规划
最长回文子串
|
|
dp[i][j]表示 i 到 j 位置是否是回文字符串,如果是,则dp[i][j]=true。
|
|
分割回文串II
|
|
将 s 分割成全是回文的子串,需要的最少分割次数,我们使用动态规划来解决这个题。
dp[i] 表示 0 到 i 范围内,分割成回文子串,需要的最少次数为 dp[i]。
递推表达式,我们要对 [0, i] 范围内的字符串进行分割,分割位置为 j,如果 [j+1,i] 范围内的字符串为是回文的,则分割次数加 1。
我们要找到最少的分割次数,所以:dp[i] = min(dp[i], dp[j]+1)。
初始化 dp 数组:每个位置都应该是分割的最大值 i。
|
|
对上面的优化,在双重循环变量i和j时,都需要判断 [j+1: i] 位置是否是回文的,
为了减少计算的次数,我们可以把 [j+1: i] 位置是否是回文的存入到一个二维数组中。
这样,就用了两次 dp,一次计算 [i:j] 位置是否是回文的 isValid 数组,一次计算分割为回文字符串需要的最少次数。
如何判断 [i: j] 是否是回文的呢?
isValid[i][j]表示 [i: j](包含 i 和 j )位置的字符串是否是回文的,如果是,值为 true,否则值为 false。
递推表达式,如果 s[i]==s[j],如果 isValid[i+1][j-1]==true,则 isValid[i][j] 值为 true。
初始化 isValid 数组,根据递推表达式,在遍历 i 时我们需要从大到小,遍历 j 时,我们需要从小到大。
应该初始化 i 和 j 相等时 isValid 数组的值,isValid[i][i]=true。
|
|
最长递增子序列的个数
分析中的代码来自 代码随想录,个人觉得本题过于复杂,先暂时跳过了。
|
|
来自代码随想录的思路:
这道题可以说是 300.最长上升子序列 的进阶版本。
1.确定 dp 数组(dp table)以及下标的含义
这道题目我们要一起维护两个数组。
dp[i]:i 之前(包括i)最长递增子序列的长度为 dp[i]
count[i]:以 nums[i] 为结尾的字符串,最长递增子序列的个数为count[i]
2.确定递推公式
在 300.最长上升子序列 中,我们给出的状态转移是:
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
即:位置 i 的最长递增子序列长度 等于 j 从 0 到 i-1 各个位置的最长升序子序列 + 1的最大值。
本题就没那么简单了,我们要考虑两个维度,一个是dp[i]的更新,一个是count[i]的更新。
那么如何更新count[i]呢?
以nums[i]为结尾的字符串,最长递增子序列的个数为count[i]。
那么在nums[i] > nums[j]前提下,如果在[0, i-1]的范围内,找到了j,使得dp[j] + 1 > dp[i],说明找到了一个更长的递增子序列。
那么以j为结尾的子串的最长递增子序列的个数,就是最新的以i为结尾的子串的最长递增子序列的个数,即:count[i] = count[j]。
在nums[i] > nums[j]前提下,如果在[0, i-1]的范围内,找到了j,使得dp[j] + 1 == dp[i],说明找到了两个相同长度的递增子序列。
那么以i为结尾的子串的最长递增子序列的个数 就应该加上以j为结尾的子串的最长递增子序列的个数,即:count[i] += count[j]。
|
|