- 基础知识:时间复杂度和空间复杂度的概念和推算
- 数据结构:数组、栈(单调栈)、队列(双端队列)、字符串、链表、哈希表、树、图、堆
- 基本算法:查找、排序、双指针、滑动窗口、模拟法、数学、贪心算法、动态规划、分治、搜索与回溯
- 主要语言:Javascript、Typescript
动态规划
某一个问题有很多重叠子问题,动态规划的求解过程中,每一个状态都一定是由上一个状态推导出来的。[状态转移方程]
动态规划解题五部曲:
- 确定dp数组以及下标的含义
- 确定递推公式/状态转移方程
- 对dp数组进行初始化
- 确定对于dp数组的遍历顺序
- 举例推导dp数组
dp问题debug思路:把dp数组打印出来,看是否按照状态转移方程进行推导。
位运算
JS提供了位操作符直接操作内存中表示数据的比特位。ES中所有数字都以IEEE 64位格式存储,但是位操作会先将数值转为32位整数再进行位操作,操作结束后再转换为64位格式。
32位表示中,最高位为符号位,0表示偶数,1表示奇数。
正数以真正的二进制格式存储。
负数x以补码的二进制编码格式进行存储。
- 首先计算x的绝对值的二进制表示;
- 将该二进制表示取反;
- 将结果加1;
位运算符:
- 波浪符:按位非,每一位取反;
- &:按位与,同时为1则结果为1;x&1除最低位外所有位都为0,因此若x为偶数,则第0位为偶数,结果为0;若x为奇数,则第0为为1,结果为1;所以利用x&1的结果可以判断x的奇偶性;
- | : 按位或,有1位为1则结果为1;
- ^ :按位异或,只在一位上是1时才返回1;
- << :左移,将所有位向左移动指定位数;
- >> :有符号右移:所有位向右移动并且保持符号;
- >>>:无符号右移:无符号右移会包括符号位一起移动,在空白位补0;
日程 | 题目 | 思路 |
---|---|---|
Day1 | 栈与队列 | |
1.用两个栈实现队列 | 利用辅助栈实现主栈入栈元素的逆序排序 | |
2.包含min函数的栈 | 将辅助栈设置为从栈底到栈顶的非严格单调递减序列,则某时刻主栈中最小的元素,即为辅助栈的栈顶元素 | |
Day2 | 链表 | |
1.从尾到头打印链表 | 1.辅助栈;2.递归; | |
2.反转链表 | 1.双指针方法遍历时进行反转;2.递归,回溯时进行修改; | |
3.复杂链表的复制 ※ | 利用哈希表辅助,哈希表的key存储旧节点,value存储对应的新节点,通过旧节点能找到其对应的新节点 | |
Day3 | 字符串 | |
1.替换空格 | ||
2.左旋转字符串 | 整体旋转一次,再在两个区间内分别旋转一次 | |
Day4 | 查找算法(简单) | 2023-3-14 |
1.数组中重复的数字 | ||
2.在排序数组中查找数字Ⅰ | ||
3.0-n-1中缺失的数字 | ||
Day5 | 查找算法(中等) | 2023-3-15 |
1.搜索二维矩阵Ⅱ ※ | 从矩阵右上角开始,左边的元素均小于该元素,下面的元素均大于该元素,类似于二叉搜索树。 1.若target小于右上角元素,则小于整列元素,此时相当于删除掉右上角元素所在的列; 2.若target大于右上角元素,则大于整行元素,此时相当于删除掉右上角元素所在的行; |
|
2.旋转数组的最小数字 | ||
3.第一个只出现一次的字符 | ES6的map数据结构遍历时的顺序等于插入时的顺序! | |
Day6 | 搜索与回溯算法(简单) | 2023-3-15 |
1.从上到下打印二叉树 | 二叉树的层序遍历,借助队列的先入先出特性来实现 | |
2.从上到下打印二叉树Ⅱ | 循环时记录每一层的节点数目,按层打印结果 | |
3.从上到下打印二叉树Ⅲ ※ (“之”字形打印) |
1.每行的打印顺序交替变化;奇数行从左到右打印,偶数行从右到左打印; 2.利用存储层序总的遍历结果的数组的长度来判断当前遍历的层数是奇数层还是偶数层;也即通过ans.length为偶数,则当前层为奇数层,则执行push操作; 若为偶数层,则执行unshift操作 |
|
Day7 | 搜索与回溯算法(简单) | |
1.树的子结构 | 1.先遍历A树找到与B树根节点的值相同的节点C(C.val === B.val); 2.判断以C为根节点的子树是否包含B树(递归判断) |
|
2.二叉树的镜像 | 递归遍历二叉树,交换每个节点的左右孩子节点。 1.初始化节点tmp,暂存root的左子节点 2.递归镜像root的右子节点root.right,将返回值赋值给左子节点 3.递归镜像root的左子节点tmp,将返回值赋值给右子节点 4.返回当前节点root(因为只是交换当前节点的孩子节点) |
|
3.对称的二叉树 | ||
Day8 | 动态规划(简单) | |
1.斐波那契数列 | ||
2.青蛙跳台阶问题 ※ | ||
3.股票的最大利润 | ||
4.使用最小花费爬楼梯 | ||
Day9 | 动态规划(中等) | 2023-3-17 |
1.连续子数组的最大和 | ||
2.礼物的最大价值 | ||
3.不同路径 | dp[ i ] [ j ] = dp[ i - 1] [ j ] + dp[ i ] [ j - 1 ] | |
4.不同路径Ⅱ ※ | 1.dp数组初始化第一行和第一列时,确定是否有障碍物,若有障碍物则第一行后续和第一列后续的格子都无法到达 2.遍历时,若当前[i,j]格子上有障碍物,那么dp[ i ] [ j ] = 0,从该格子无法到达右格子和下格子; |
|
Day10 | 动态规划(中等) | 2023-3-18 |
1.把数字翻译成字符串 ※ | 1.本质上跟跳台阶的问题类似,因为翻译一次只能翻译一个数字(0-9)或者两个数字(10-25) 2.因此,若数字的位数为n,则可以拆分为X1X2X3...Xn,则dp[i]表示X1...Xi这个数字的翻译数目 3.因为翻译时,每次只能选择翻译一个数字,或者两个数字,所以dp[i]只能由dp[i-1]和dp[i-2]决定; 4.若Xi-1X可被翻译(位于10-25),则表示既可以从i-2跳两个数字到i,也可以从i-1跳一个数字到i;(相当于可跳1阶或者2阶) 5.若Xi-1X不可被翻译,则只能从i-1到i;(相当于只能跳1阶) |
|
2.最长不含重复字符的子字符串 | ||
Day11 | 双指针(简单) | 2023-3-19 |
1.删除链表的节点 | pre指向前一个节点,cur指向当前节点 | |
2.链表中倒数第k个节点 | 初始时pre和cur都指向头节点,然后让cur向后移动k个节点,使得cur和pre之间的差值保持为k 不断向后同时移动pre和cur,当cur为空时,pre即为倒数第k个节点 |
|
leetcode第337场周赛 | 2023-3-19 | |
1.奇偶位数 ※ 【位操作】 | 基础的位运算,x&1判断x的最低位为0还是1,x^=1可以让x加1(偶数)或减一(奇数); x>>=1,让x所有数位向右移动1位; |
|
2.检查骑士巡视方案 | 第一次遍历时利用一个哈希表辅助计算每次巡视的坐标值; 第二次遍历时判断下一个位置相对当前位置是否符合规则(象棋中的马走日); !注意题目要求起点在左上角,即grid[0][0]必须要为0; |
|
3.美丽子集的数目 | 回溯算法计算数组的子集,判断子数组是否满足条件 | |
Day12 | 双指针(简单) | 2023-3-20 |
1.合并两个排序的链表 | ||
2.两个链表的第一个公共节点 ※ | 非常浪漫的一道题目 | |
Day13 | 双指针(简单) | 2023-3-21 |
1.调整数组顺序使奇数位于偶数前面 | 双指针,左指针寻找偶数,右指针寻找奇数,交换左右指针指向的元素 | |
2.和为s的两个数字 | 双指针,缩小区间 | |
3.翻转单词顺序 | ||
Day14 | 搜索与回溯算法(中等) | 2023-3-22 |
1.矩阵中的路径 ※ | DFS搜索 + 剪枝 + 回溯 | |
2.机器人的运动范围 | ||
Day15 | 搜索与回溯算法(中等) | 2023-3-23 |
1.二叉树中和为某一值的路径 ※ | DFS遍历 + 路径记录 + 回溯 | |
2.二叉搜索树与双向链表 ※ | 二叉搜索树的中序遍历为一个递增序列; 对中序遍历结果进行遍历,修改每个节点的left和right指针; |
|
3.二叉搜索树的第K大节点 | 中序遍历生成递增序列,返回倒数第k个元素 | |
Day16 | 排序(简单) | 2023-3-24 |
1.把数组排成最小的数 | 将数组排序再拼接 | |
2.扑克牌中的顺子 | 只有三种情况: 1.没有王,五个顺子,此时max-min = 4 2.一个王,四张顺子,此时max-min = 3 3.两个王,三张顺子,此时max-min = 2 因此,遍历数组,如果是0则跳过,如果set中存在重复元素,则返回false。 判断集合中最大元素和最小元素的差是否小于5,小于则返回true |
|