LeeCode三百题-1
[TOC]
代码工程获取
git clone --depth=1 https://gitee.com/SevDaisy/LeeCode300.git |
#1 两数之和
- 题目保证最多只有一个答案
- 用
HashMap<Integer, Integer>做查询即可。 HashMap的K-V存储内容为<value,index>
- 用
- 题目要求数组中同一个元素在答案里不能重复出现
- 先查看当前
HashMap中有没有答案 - 再将当前遍历对象加入
HashMap - 如此可保证,返回的答案匹配肯定不会重复。
- 先查看当前
package Order300; |
#2 两数相加
- 同步遍历
l1 l2- 并相加配对节点
- 若
l1 l2长度不匹配则,长度不足者值取零
- 因为不确定
l1 l2谁更长。因此新建链表head-tail用于存储l1 l2节点配对相加的结果head指针用于返回这个链表tail指针用于执行尾插法
- 对于
val1+val2 >= 10的情况,在循环外保留变量carry用于保存上一次加法的进位值。 - 也就是说
val1+val2+carry才是真正的sum
package Order300; |
#3 无重复字符的最长子串
- 滑动窗口类问题
- 双指针 - 左右指针
- 判断重复字符
HashSet<Character>
package Order300; |
#4 寻找两个正序数组的中位数 困难
- 二叉搜索应用题
- 二分搜索的基本操作:
mid值的计算、left/right的转移、mid值的可能范围,仍相当不熟练 - 中位数 => 概念转换为
- => 数组左边的元素都不大于数组右边的元素
- => 数据左边的元素至多比数据右边的元素多一个
package Order300; |
#5 最长回文子串
- 有三种解法
- 动态规划
- 中心扩展 —— 我的直觉
Manacher算法 —— 最难但是效果最好 —— 《左神》P535 有详细讲解
Manacher太花时间了,先跳过。回头再补习Manacher算法
package Order300; |
#6 Z字形变换
我感觉更像是
N字形变换
- 关键是,数组中的掉头/拐弯问题的
模范代码: - 循环之前,设置
pos初值为合法值 - 循环中:
- 先对
pos位进行操作 - 再看要不要变方向
- 变方向的条件是 —— 用
||连接- 正向且再走一步就是正向非法值
- 逆向且再走一步就是逆向非法值
- 变方向的条件是 —— 用
- 最后,按方向前进一步
- 先对
package Order300; |
#7 整数反转
- 前导0、后缀0的管理 —— 其实不是问题
- 溢出处理 —— 需要返回0 —— 溢出条件还蛮有意思的。
- 负数的处理 —— 不用
flag反而更方便 - 提取变量(
常量)来简化过长的条件表达式。
package Order300; |
#8 字符串转换整数 (atoi)
- 可以正常做输入流匹配
- 当然也可以,有限自动机 安排
<space> |
+ or - |
Number | else | |
|---|---|---|---|---|
| ==start== | start | sign | num | end |
| ==sign== | end | end | num | end |
| ==num== | end | end | num | end |
| ==end== | end | end | end | end |
溢出判断 的错误写法
int old = this.val;
int cur = this.val * 10 + (c - '0');
if ((cur - (c - '0')) / 10 != old) {
overflow = true;
}即使溢出了,
(cur - (c - '0')) / 10 == old依旧成立正确的溢出判断:
- 使用
Long存储this.val,并用Math.max(val,Integer.MIN_VALUE)和Math.min(...)来做截断 - 使用
int32存储this.val,并在其接近Integer.MIN_VALUE/10的时候判断溢出
- 使用
package Order300; |
#9 回文数
- 利用特殊情况,过滤掉一些不需要计算的查询
x == 0x < 0 || x % 10 == 0
- 字符串法
10~12ms - 数学演算法
150+ms
package Order300; |
#10 正则表达式匹配
两个办法
自动机 (双指针+DFS+回溯)
动态规划 —— 官方题解写的还好,不过留给读者的问题我觉得是骗人的
在上面的状态转移方程中,如果字符串 pp 中包含一个「字符 + 星号」的组合(例如 a*),那么在进行状态转移时,会先将 a 进行匹配(当 p[j]p[j] 为 a 时),再将 a* 作为整体进行匹配(当 p[j]p[j] 为 * 时)。然而,在题目描述中,我们必须将 a* 看成一个整体,因此将 a 进行匹配是不符合题目要求的。看来我们进行了额外的状态转移,这样会对最终的答案产生影响吗?这个问题留给读者进行思考。
因为它代码里的
dp数组是从[i][j]向[0][0]遍历的,根本不存在所谓的因此将 a 进行匹配
坑点 —— 自动机原理,双指针+DFS+回溯:
- 因为:
*是0次或无数次 - 所以。如果
mode中当前位没能匹配——如果mode的下一位是*的话,就可以跳过mode中的当前位了 - 所以。每次
*位出现,若匹配成功,有用和不用在两个选择。 - 所以。遇到的即使是
.,也需要考虑要不要用后面的'*'来跳过这个.
- 因为:
关键
- 动态规划的时候,要设计好方向
- 比如这题。从尾部往前转移,是非常好的想法,大大简化了状态转移方程
==动态规划算法,回头再看==
- 这个状态转移方程好晕啊。这题从昨天晚上写到现在
21:58快写吐了。 - 等以后熟练一点再回来看吧。怂。
- 这个状态转移方程好晕啊。这题从昨天晚上写到现在
package Order300; |