极客时间 算法训练营 毕业总结

原文链接
本文链接:https://blog.csdn.net/leacock1991/article/details/103554929

不知不觉8周的算法训练营也接近尾声,这期间训练营对自己的影响有三方面

  • 一方面是收获了刻意练习,终身成长这些可以产生长远影响的思想,这里推荐三本书 卡罗尔·德韦克的《终身成长》、安德斯·艾利克森和罗伯特·普尔的《刻意练习》以及彼得·布朗等的《认知天性》
  • 一方面是在自己对算法与数据结构的态度与认知上,从之前的抗拒和一提到就觉得很难,到接受和乐在其中的转变,从算法与数据结构大概是这样,到有一个脉络清晰的知识结构的转变
  • 一方面就是知识本身,下面将数据结构与算法总体回顾下

数据结构

一维

  • 基础: 数组 array (string),链表 linked list
  • 高级: 栈 stack,队列 queue,双端队列 deque,集合 set,映射 map (hash or map),etc

涉及题目:
栈 stack: 括号匹配问题、直方图、接雨水
队列 queue: 滑动窗口

二维

  • 基础: 树 tree,图 graph
  • 高级: 二叉搜索树 binary search tree (red-black tree,AVL),堆 heap,并查集 disjoint set,字典树 Trie,etc

特殊

  • 位运算 Bitwise,布隆过滤器 BloomFilter
  • LRU Cache

时间复杂度图

https://www.bigocheatsheet.com/

在这里插入图片描述

主定理

https://en.wikipedia.org/wiki/Master_theorem_(analysis_of_algorithms)

在这里插入图片描述

  • 一维数组二分查找:每次排除一半,故为O(log n)
  • 二叉树的遍历:可以理解成每个节点被访问且仅访问一次,故为O(n)
  • 二维矩阵的二分查找:O(n)
  • 归并排序:O(n logn)

数据结构思维导图

在这里插入图片描述

算法

  • if-else,switch ——> branch
  • for,while loop ——> literation
  • 递归 Recursion (Divide & Conquer ,Backtrace)

所有高级算法或数据结构最后都会转换成以上三种

  • 搜索 Search:深度优先搜索 Depth first search, 广度优先搜索 Breadth first search,A*,etc
  • 动态规划 Dynamic Programming (递归+备忘录 或 迭代+DP方程)
  • 二分查找 Binary Search
  • 贪心 Greedy
  • 数学 Math,几何 Geometry

算法 思维导图

在这里插入图片描述

代码模板

这里列举部分模板,其他模板 并查集 Disjoint Set、布隆过滤器、LRU Cache、初级排序、特殊排序等模板可以参看之前总结

递归模板

def recursion(level, param1, param2, ...): 
    # 递归终止条件
    if level > MAX_LEVEL: 
	   process_result 
	   return 
    # 处理当前层逻辑
    process(level, data...) 
    # 往下一层
    self.recursion(level + 1, p1, ...) 
    # 清理当前层

 
 

分治模板

def divide_conquer(problem, param1, param2, ...): 
  # 递归终止条件
  if problem is None: 
	print_result 
	return 
  # 处理当前层逻辑(分解子问题)
  data = prepare_data(problem) 
  subproblems = split_problem(problem, data) 
  # 往下一层(解决子问题)
  subresult1 = self.divide_conquer(subproblems[0], p1, ...) 
  subresult2 = self.divide_conquer(subproblems[1], p1, ...) 
  subresult3 = self.divide_conquer(subproblems[2], p1, ...)# 合并子结果(合并结果)
  result = process_result(subresult1, subresult2, subresult3,)
   # 清理当前层

归并排序模板

def merge_sort(arr, left, right):
    """
    归并排序(Merge Sort)
    """
    if right <= left:   # 递归终止条件
        return
    # 先输入序列分成两个长度为n/2的子序列并对这两个子序列分别采用归并排序
    mid = (left + right) >> 1  # (left + right) / 2
    merge_sort(arr, left, mid)   #  注意 mid
    merge_sort(arr, mid + 1, right)
    # 排序好的子序列合, 重点 merge 函数的实现
    merge(arr, left, mid, right)

def merge(arr, left, mid, right):
# left , mid 有序 mid + 1 , right 有序
temp = [0 for _ in range( right - left + 1)] # 中间数组, 需要额外的内存空间
i = left
j = mid + 1
k = 0
while i <= mid and j <= right: # 合并 left , mid 有序数列 和 mid + 1 , right 有序数列
if arr[i] <= arr[j]:
temp[k] = arr[i]
k, i = k + 1, i + 1
else:
temp[k] = arr[j]
k, j = k + 1, j + 1
while i <= mid: # left , mid 有序数列 剩余
temp[k] = arr[i]
k, i = k + 1, i + 1
while j <= right: # mid + 1 , right 有序数列 剩余
temp[k] = arr[j]
k, j = k + 1, j + 1

<span class="token comment"># 将 排序好的 temp 放入 arr 中</span>
<span class="token keyword">for</span> p <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token builtin">len</span><span class="token punctuation">(</span>temp<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    arr<span class="token punctuation">[</span>left <span class="token operator">+</span> p<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">[</span>p<span class="token punctuation">]</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

快速排序模板

def quick_sort(arr, begin, end):
    """
     快速排序(Quick Sort)
    """
    if end <= begin:    # 递归终止条件
        return
    # 先找标杆 pivot,将小元素放 pivot左边,大元素放右侧; 重点 partition 函数的实现
    pivot = partition(arr, begin, end)
    # 然后依次对标杆 pivot 右边和右边的子数组继续快排
    quick_sort(arr, begin, pivot-1)	  # 注意 不包括标杆
    quick_sort(arr, pivot + 1,end)

def partition(arr, begin, end):
“”"
partition 函数 用于查找 标杆位置并处理排序数组
“”"

pivot = end # 选择 end 为标杆
min_index = begin # counter: ⼩于pivot的元素的下标
for i in range(begin, end): # 这里不包含 标杆位置
if arr[i] < arr[pivot]: # i 位置数据 小于 a[pivot]
arr[min_index], arr[i] = arr[i], arr[min_index] # 交换 arr[min_index], arr[i] 数据位置
min_index += 1 # 递增
# 循环结束 min_index 就为 标杆应该所在位置
arr[min_index], arr[pivot] = arr[pivot], arr[min_index]
return min_index

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

DFS 模板

递归实现:

#递归前处理
visited = set()  # 节点是否被访问

def dfs(node,visited):
# 递归终止条件
if node in visited: # 是否被访问
return

<span class="token comment"># 递归到下一层前处理(当前层处理)</span>
visited<span class="token punctuation">.</span>add<span class="token punctuation">(</span>node<span class="token punctuation">)</span> 
<span class="token comment"># 其它处理</span>

<span class="token comment"># 递归到下一层</span>

<span class="token keyword">for</span> next_node <span class="token keyword">in</span> node<span class="token punctuation">.</span>children<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> 
    <span class="token keyword">if</span> <span class="token operator">not</span> next_node <span class="token keyword">in</span> visited<span class="token punctuation">:</span> 
		dfs<span class="token punctuation">(</span>next_node<span class="token punctuation">,</span> visited<span class="token punctuation">)</span>

<span class="token comment"># 递归下层次返回后处理</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

迭代实现:
dfs=栈,压栈,出栈

def dfs(node,visited):
<span class="token keyword">if</span> tree<span class="token punctuation">.</span>root <span class="token keyword">is</span> <span class="token boolean">None</span><span class="token punctuation">:</span> 
	<span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> 
<span class="token comment"># 迭代前处理</span>
visited<span class="token punctuation">,</span> stack <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>tree<span class="token punctuation">.</span>root<span class="token punctuation">]</span>    <span class="token comment"># 辅助栈 压栈</span>
<span class="token comment"># 迭代终止条件</span>
<span class="token keyword">while</span> stack<span class="token punctuation">:</span> 
    <span class="token comment"># 迭代</span>
    node <span class="token operator">=</span> stack<span class="token punctuation">.</span>pop<span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token comment"># 出栈</span>
    visited<span class="token punctuation">.</span>add<span class="token punctuation">(</span>node<span class="token punctuation">)</span>   <span class="token comment"># 标记访问</span>

    rocess <span class="token punctuation">(</span>node<span class="token punctuation">)</span>   <span class="token comment"># 当前节点处理</span>

    nodes <span class="token operator">=</span> generate_related_nodes<span class="token punctuation">(</span>node<span class="token punctuation">)</span>  <span class="token comment"># 生成相关节点</span>
    stack<span class="token punctuation">.</span>push<span class="token punctuation">(</span>nodes<span class="token punctuation">)</span> <span class="token comment"># 压栈</span>
<span class="token comment"># 迭代后处理</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

BFS 模板

迭代实现:

bfs=队列,入队列,出队列

def bfs(graph, start, end):
    # 迭代前处理
    queue = [] # 辅助队列
    queue.append([start])   # 入队列
    visited.add(node)   # 标记访问
    # 迭代终止条件
    while queue:
        # 迭代  
        node = queue.pop(0)  # 出队列
        visited.add(node)   # 标记访问
    rocess <span class="token punctuation">(</span>node<span class="token punctuation">)</span>   <span class="token comment"># 当前节点处理</span>
    nodes <span class="token operator">=</span> generate_related_nodes<span class="token punctuation">(</span>node<span class="token punctuation">)</span>  <span class="token comment"># 生成相关节点</span>
    queue<span class="token punctuation">.</span>push<span class="token punctuation">(</span>nodes<span class="token punctuation">)</span> <span class="token comment"># 入队列</span>

<span class="token comment"># 迭代后处理     </span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

二分查找代码模板


left, right = 0, len(array) - 1 
while left <= right: 
	  # mid = (left + right) / 2
      mid = low + (high-low)/2
	  if array[mid] == target: 
		    # 找到目标
		    break or return result 
	  elif array[mid] < target: 
		    left = mid + 1 
	  else: 
		    right = mid - 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Trie树模板

class Trie:
<span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
    self<span class="token punctuation">.</span>root <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>  <span class="token comment"># 根节点</span>
    self<span class="token punctuation">.</span>endofword <span class="token operator">=</span> <span class="token string">"#"</span>    <span class="token comment"># 标识是否是一个完整的单词</span>
    

<span class="token keyword">def</span> <span class="token function">insert</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> word<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token boolean">None</span><span class="token punctuation">:</span>
    <span class="token comment"># 插入操作</span>
    node <span class="token operator">=</span> self<span class="token punctuation">.</span>root    <span class="token comment"># 根节点</span>
    <span class="token keyword">for</span> char <span class="token keyword">in</span> word<span class="token punctuation">:</span>   <span class="token comment"># 遍历单词 word 中每个字符</span>
        node <span class="token operator">=</span> node<span class="token punctuation">.</span>setdefault<span class="token punctuation">(</span>char<span class="token punctuation">,</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment"># 字典形式依次将字符保存到树的每一层中</span>
        <span class="token comment"># dict.setdefault(key, default=None) 如果 key 在 字典中,返回对应的值。</span>
        <span class="token comment"># 如果不在字典中,则插入 key 及设置的默认值 default,并返回 default ,default 默认值为 None。</span>
    node<span class="token punctuation">[</span>self<span class="token punctuation">.</span>endofword<span class="token punctuation">]</span> <span class="token operator">=</span> self<span class="token punctuation">.</span>endofword   <span class="token comment"># 完整单词标识</span>
    

<span class="token keyword">def</span> <span class="token function">search</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> word<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token builtin">bool</span><span class="token punctuation">:</span>
    <span class="token comment"># 查找操作</span>
    node <span class="token operator">=</span> self<span class="token punctuation">.</span>root
    <span class="token keyword">for</span> char <span class="token keyword">in</span> word<span class="token punctuation">:</span>   <span class="token comment"># 遍历单词 word 中每个字符</span>
        <span class="token keyword">if</span> char <span class="token operator">not</span> <span class="token keyword">in</span> node<span class="token punctuation">:</span>    <span class="token comment"># 未找到</span>
            <span class="token keyword">return</span> <span class="token boolean">False</span>
        node <span class="token operator">=</span> node<span class="token punctuation">.</span>get<span class="token punctuation">(</span>char<span class="token punctuation">)</span>   <span class="token comment"># 找到进入下一结点</span>
    <span class="token keyword">return</span> self<span class="token punctuation">.</span>endofword <span class="token keyword">in</span> node <span class="token comment"># 是否为完整的单词</span>
    

<span class="token keyword">def</span> <span class="token function">startsWith</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> prefix<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token builtin">bool</span><span class="token punctuation">:</span>
    <span class="token comment"># 字典树中是否有以 prefix 为前缀的单词</span>
    node <span class="token operator">=</span> self<span class="token punctuation">.</span>root
    <span class="token keyword">for</span> char <span class="token keyword">in</span> prefix<span class="token punctuation">:</span> <span class="token comment"># 遍历 前缀 prefix</span>
        <span class="token keyword">if</span> char <span class="token operator">not</span> <span class="token keyword">in</span> node<span class="token punctuation">:</span>
            <span class="token keyword">return</span> <span class="token boolean">False</span>
        node <span class="token operator">=</span> node<span class="token punctuation">.</span>get<span class="token punctuation">(</span>char<span class="token punctuation">)</span> 
    <span class="token keyword">return</span> <span class="token boolean">True</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

学习要点

基本功是区别业余和职业选手的根本。深厚功底来自于 — 过遍数

最大的误区:只做一遍

五毒神掌

刻意练习 - 练习缺陷弱点地方、不舒服、枯燥

反馈 - 看题解、看国际版的高票回答

切题四件套

  • Clarification
  • Possible Solutions
    • compare (time/space)
    • optimal (加强)
  • Coding(多写)
  • Test cases

五毒神掌

第一遍
五分钟:读题 + 思考
直接看解法:多看几种,比较解法优劣
背诵、默写好的解法
第二遍
马上自己写 ——> Leetcode提交
多种解法比较、体会 ——> 优化!
第三遍
过了一天后,再重复做题
不同解法的熟练程度——>专项练习
第四遍
过了一周后:反复回来练习相同的题目
第五遍
面试前一周恢复性训练

经典习题

爬楼梯: https://leetcode-cn.com/problems/climbing-stairs/

硬币兑换: https://leetcode-cn.com/problems/coin-change/

有效括号: https://leetcode-cn.com/problems/valid-parentheses/

括号生成: https://leetcode-cn.com/problems/generate-parentheses/

柱状图中最大的矩形: https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

滑动窗口最大值: https://leetcode-cn.com/problems/sliding-window-maximum/

二叉树遍历:

验证二叉搜索树: https://leetcode-cn.com/problems/validate-binary-search-tree/submissions/

股票买卖:

打家劫舍:

编辑距离: https://leetcode-cn.com/problems/edit-distance/

最长上升子序列: https://leetcode-cn.com/problems/longest-increasing-subsequence/

最长公共子序列: https://leetcode-cn.com/problems/longest-common-subsequence/

字母异位词分组: https://leetcode-cn.com/problems/group-anagrams/

回文串:

通配符匹配: https://leetcode-cn.com/problems/wildcard-matching/

高级数据结构(Trie、 BloomFilter、 LRU cache、 etc)

                                </div><div><div></div></div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-60ecaf1f42.css" rel="stylesheet">
                            </div>
</article>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值