视频课已上传B站 【7 天掌握算法面试必考知识点 - 覃超老师】
覃超老师的算法课很实在,干货满满!虽然这只是体验课,还没购买正式课,认真听还是会有很大收获的!
学习技巧:
1)好记性不如烂笔头, 因此请尝试
2)给每一道自己写过,看过的题目写一篇解题报告,
3)对相关一类题型的总结报告,
算法对于程序员的重要性不言而喻。希望这 7 天的学习能够帮助你掌握高效的学习方法,逐渐把算法能力强化为自己的内功。我也从来不相信“速成”、“捷径”之类的宣传语,我们想要把算法学明白,就需要付出不亚于任何人的努力。开课之前,也请你做好充足的时间和心理准备。学习是自己的事情,送到嘴边的饭还得你自己细嚼慢咽才能消化,所以更多的还是需要你自己练习,自己思考。
Leecode解题完毕,将网址中的-cn去掉,可以去到国际站看更多的解题思路
编程题
节选视频中讲解的两道编程题,和链接中的三道编程题,老师多用java编写,我比较习惯用python。有的就用老师说的解题思路换个语言编写,有的是参考其他解题思路写的,还有自个想的(可能略挫,见谅!如有错 / 有不恰当的地方 / 有更好优化方法的 都可以留言讨论)
1.移动0
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序
【链接】 https://leetcode-cn.com/problems/move-zeroes/
'''
示例:
输入: [0,1,0,3,12] 输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。尽量减少操作次数。
'''
def moveZeroes(nums): # 方法1
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
# 我假设输入[1,0,3,0,5],下面也是针对这个序列的分析
j = 0
for i in range(len(nums)):
print('nums[i] = ',nums[i])
if nums[i] != 0:
nums[j] = nums[i] # 先查找非0的,用新下标j存着
print("if-1",nums)
# 遇到0的时候,i会+1,j不会,那i就会比j大,在if-1中的nums还没调整好
# if-2这里再去调整新nums,如我刚才前3是[1,3,3],调整后是[1,3,0]
# 至少到这步,也完成了前3个数的 0的后移
if i!=j:
nums[i] = 0
print("if-2",nums)
j = j+1
print("nums result = ",nums)
# i=0 j=0 num[i]=1
# if-1:num = [1,]
# i=1 j=1 num[i]=0
# i=2 j=1 num[i]=3 num[j]=3
# if-1:num = [1,3,3]
# if-2:num = [1,3,0]
# i=3 j=2 num[i]=0 num[j]=/ 这里的总nums是[1,3,0,0,5]
# i=4 j=2 num[i]=5 num[j]=5
# if-1:num = [1,3,5,0,5]
# if-2:num = [1,3,5,0,0]
# 第2个if是把nums的最后一个数(最新的i下标)变0,完成后移操作
def moveZeroes2(nums): # 方法1更快
for i in range(len(nums)):
if nums[i]==0:
nums.remove(0)
nums.append(0)
print(nums)
nums = [1,0,3,0,5]
moveZeroes(nums)
# 思路2:新开个数组存放(不符合题目要求)
2.删除排序数组中的重复项
给定一个 排序(已排序好的) 数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
【链接】 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/
'''
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
'''
class Solution(object):
def removeDuplicates(nums):
"""
:type nums: List[int]
:rtype: int
"""
p = 0
for q in range(1,len(nums)):
if nums[p] != nums[q]:
p=p+1
nums[p] = nums[q]
# print(p)
del nums[p+1:len(nums)] # 删除后面糟糕的数据,才能返回移除后数组的新长度,否则执行出错
print(nums)
nums = [0,0,1,1,1,2,2,3,3,4]
Solution.removeDuplicates(nums)
附上一种自个画的双指针图,其中q+1是每次循环都会进行的操作,就不用写了
3.二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历。
【链接】https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
'''
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,2,3]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
'''
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def preorderTraversal(self, root):# 根左右
"""
:type root: TreeNode
:rtype: List[int]
"""
stack,rst = [root],[]
while stack:
i = stack.pop()
if isinstance(i,TreeNode):
stack.extend([i.right,i.left,i.val]) # 一句搞定
elif isinstance(i,int):
rst.append(i)
return rst
4.括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
【链接】https://leetcode-cn.com/problems/generate-parentheses/
先来看老师的解法,严格按照递归模板来做的哈
01 初级版本:生成n=3(共2(2x3)=64种)的所有组合
02 中级版本
- terminator 终止条件:‘(’ 和 ‘)’都用完了,再输出 s
- drill down 下探到下一层和处理一起进行:判断两个
- 左括号’(’ 只要还没用完(3个),那就可以添加
- 右括号’)’ 必须小于左括号的个数时才能添加
然后呢,我用py写一个
按照下面这个套路
class Solution():
def generateParenthesis(self,n):
"""
:type n: int
:rtype: List[str]
"""
result = []
par_str = ''
def generate(left,right,n,par_str):
if (left==n) and (right==n): # terminator
result.append(par_str)
# print(par_str)
# return result
if left<n:
generate(left+1, right, n, par_str+'(')
if left>right:
generate(left, right+1, n, par_str+')')
generate(0,0,n,par_str)
return result
# def generateParenthesis(self,n): # 参考
# res = []
# cur_str = ''
# def dfs(cur_str, left, right, n):
# """
# :param cur_str: 从根结点到叶子结点的路径字符串
# :param left: 左括号已经使用的个数
# :param right: 右括号已经使用的个数
# :return:
# """
# if left == n and right == n:
# res.append(cur_str)
# return
# if left < n:
# dfs(cur_str + '(', left + 1, right, n)
# if right < n:
# dfs(cur_str + ')', left, right + 1, n)
# dfs(cur_str, 0, 0, n)
也可以看很多国内外牛人解法
5.二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
【链接】https://leetcode-cn.com/problems/maximum-depth-of-binary-tree
'''
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
'''
通过下面这个的动图和静图可以较清晰的表示 递归算法 的解题思路了
'''
很多二叉树的题目,用递归写起来就非常简单。
再来分析下递归的两个条件:
递归终止条件:当节点为空时返回
再次递归计算 max( 左节点最大高度,右节点最大高度)+1
终止条件很好理解,节点为空了,就返回0,也就是高度为0。
'''
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def maxDepth(self, root): # 法1
"""
:type root: TreeNode
:rtype: int
"""
# 递归:max(遍历左,遍历右) +1
if root is None:
return 0
else:
left_height = self.maxDepth(root.left)
right_height = self.maxDepth(root.right)
return max(left_height, right_height) + 1
def maxDepth(self, root): # 法2 j版
# 如果节点为空,那么深度就是0
if(not root):
return 0
# 否则递归的计算 max(左子树的最大深度,右子树的最大深度)
# 不管左子树,右子树是否为空,他们的父节点肯定是不为空
# 所以计算出的总深度要把父节点也要加上,也就是 +1
return max( self.maxDepth(root.left), self.maxDepth(root.right) ) + 1
相关链接
-
Day1.参考链接
如何理解算法时间复杂度的表示法【https://www.zhihu.com/question/21387264】
Master theorem 【https://en.wikipedia.org/wiki/Master_theorem_(analysis_of_algorithms)】
主定理 【https://zh.wikipedia.org/wiki/%E4%B8%BB%E5%AE%9A%E7%90%86】 -
Day2.参考链接
Java 源码分析(ArrayList)【http://developer.classpath.org/doc/java/util/ArrayList-source.html】
Linked List 的标准实现代码【https://www.geeksforgeeks.org/implementing-a-linked-list-in-java-using-class/】
Linked List 示例代码【http://www.cs.cmu.edu/~adamchik/15-121/lectures/Linked%20Lists/code/LinkedList.java】
Java 源码分析(LinkedList)【http://developer.classpath.org/doc/java/util/LinkedList-source.html】
LRU Cache - Linked list: LRU 缓存机制【https://leetcode-cn.com/problems/lru-cache/】
Redis - Skip List:跳跃表、为啥 Redis 使用跳表(Skip List)而不是使用 Red-Black?【https://www.zhihu.com/question/20202931】
跳跃表【https://redisbook.readthedocs.io/en/latest/internal-datastruct/skiplist.html】 -
Day3.两道编程题
删除排序数组中的重复项【https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/】
盛最多水的容器【https://leetcode-cn.com/problems/container-with-most-water/】 -
Day4.参考链接:
二叉搜索树 Demo【https://visualgo.net/zh/bst?slide=1】
思考题:树的面试题解法一般都是递归,为什么? -
Day5.两道编程题:
N 叉树的前序遍历【https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/】
二叉树的前序遍历【https://leetcode-cn.com/problems/binary-tree-preorder-traversal/】
参考链接:树的遍历 Demo【https://visualgo.net/zh/bst?slide=1】 -
Day6.参考链接
递归代码模板:https://shimo.im/docs/EICAr9lRPUIPHxsH/read- Python 代码模板
def recursion(level, param1, param2, ...): # recursion terminator if level > MAX_LEVEL: process_result return # process logic in current level process(level, data...) # drill down self.recursion(level + 1, p1, ...) # reverse the current level status if needed
- Java 代码模板
public void recur(int level, int param) { // terminator if (level > MAX_LEVEL) { // process result return; } // process current logic process(level, param); // drill down recur( level: level + 1, newParam); // restore current status }
- c++代码模板
void recursion(int level, int param) { // recursion terminator if (level > MAX_LEVEL) { // process result return ; // process current logic process(level, param); // drill down recursion(level + 1, param); // reverse the current level status if needed }
-
Day7.两道编程题:
二叉树的最大深度【https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/】
验证二叉搜索树【https://leetcode-cn.com/problems/validate-binary-search-tree/】 -
直播
https://github.com/Snailclimb/JavaGuide
https://github.com/CyC2018/CS-Notes
https://juejin.im/entry/6844903474195333128
费曼学习法
光看不练
系统设计- github: https://github.com/donnemartin/system-design-primer
- 中文: https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md
homework
Day5
- 【二叉树的中序遍历】https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
- 【二叉树的前序遍历】https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
- 【N叉树的后序遍历】https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/
- 【N叉树的前序遍历】https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/
- 【N叉树的层序遍历】https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/
Day 7
- 【翻转二叉树】https://leetcode-cn.com/problems/invert-binary-tree/description/
- 【验证二叉搜索树】https://leetcode-cn.com/problems/validate-binary-search-tree/
- 【二叉树的最大深度】https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
- 【二叉树的最小深度】https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
- 【二叉树的序列化与反序列化】https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/
- 【二叉树的最近公共祖先】https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
- 【从前序与中序遍历序列构造二叉树】https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
- 【组合】https://leetcode-cn.com/problems/combinations/
- 【全排列】https://leetcode-cn.com/problems/permutations/
- 【全排列 II】https://leetcode-cn.com/problems/permutations-ii/
五步刷题法(五毒神掌)
刷题第一遍:
5分钟:读题+思考(建议不要超过15分钟)
直接看解法:注意!多解法,比较优劣
背诵、默写好的解法
第二遍:
马上自己写–> LeetCode提交 debug至完成
多种解法比较、体会–>优化!
看时间空间 效率 (执行时间和内存消耗)
第三遍:
过了一天后,再重复做题
不同解法的熟练程度–>专项练习
第四遍:
过了一周:反复回来练习相同题目
对于不熟的题目专项练习。
第五遍:
如果有面试,面试前一周进行恢复式训练