你读过哪些让你醍醐灌顶的Java代码?

比如困扰我很久的二分法
在这里插入图片描述
再比如考察频率贼高的深度优先搜索(DFS)
在这里插入图片描述
很多大佬看完会diss我:这些代码有啥NB的,我也能写出来,但问题是它真的好用啊,可以说是算法面试的刷题利器!

这份算法模板是我在《九章算法班》的首节免费试听讲座上拿到的,主讲人令狐冲分享了很多算法面试的技巧,感兴趣的话你们也可以去免费试听下~

接下来,具体说下这份模板怎么用,又是怎么让我感到“醍醐灌顶”的。

排序算法

排序算法一般是考察其中的快速排序和归并排序及相关的题,必须背诵这两个排序。

先来看这道例题,大家可以试着做一下:
LintCode 463. 整数排序
如果做不出来,就可以参考这个模板。

复杂度

  • 时间复杂度:

  • 快速排序(期望复杂度) : O(nlogn)

  • 归并排序(最坏复杂度) : O(nlogn)

  • 空间复杂度:

  • 快速排序 : O(1)

  • 归并排序 : O(n)

代码模板
在这里插入图片描述
接下来,试着套用模板做这道题:
LintCode 464. 整数排序 II

能做出来你也就出师了,接下来就是通过反复练习+理解思路不断巩固,我现在在面试中遇到排序算法基本可以直接秒。
在这里插入图片描述

宽度优先搜索 BFS

再说说DFS的好兄弟BFS。宽度优先搜索的考察频率高,实现一般都不难,在准备算法面试中可以优先考虑搞定它。

依葫芦画瓢一下,会使用DFS来解题的情况包括:

使用条件

  1. 拓扑排序(100%)
  2. 出现连通块的关键词(100%)
  3. 分层遍历(100%)
  4. 简单图最短路径(100%)
  5. 给定一个变换规则,从初始状态变到终止状态最少几步(100%)

复杂度

  • 时间复杂度:O(n + m)
  • n 是点数, m 是边数
  • 空间复杂度:O(n)

代码模板

在这里插入图片描述
接下来,结合这几道例题来理解这份模板:

LintCode 974. 01 矩阵(分层遍历)

LintCode 431. 找无向图的连通块

LintCode 127. 拓扑排序

动态规划

再来说个特别的,最令人头大的动态规划。

令狐老师在《FB面试官揭露算法技巧》的讲座中有提到动态规划的解题法则

首先要搞懂动态规划的使用场景

这些情况不适用动规,不要被坑

  • 找所有具体的方案(准确率99%)
  • 输入数据无序(除了背包问题外,准确率60%~70%)
  • 暴力算法已经是多项式时间复杂度(准确率80%)

这些情景可以考虑使用动态规划,但也别钻牛角尖:

  • 求方案总数(90%)
  • 求最值(80%)
  • 求可行性(80%)

接下来,搞懂第一个重要概念:动态规划四要素(对比递归的四要素):

  • 状态 (State) – 递归的定义
  • 方程 (Function) – 递归的拆解
  • 初始化 (Initialization) – 递归的出口
  • 答案 (Answer) – 递归的调用

现在,我们就可以根据动态规划的不同类型找到不同解法:

①背包型

  • 给出 n 个物品及其大小,问是否能挑选出一些物品装满大小为m的背包
  • 题目中通常有“和”与“差”的概念,数值会被放到状态中
  • 通常是二维的状态数组,前 i 个组成和为 j 状态数组的大小需要开 (n + 1) * (m + 1)

对应解法

a.背包

  • 状态 state
dp[i][j] 表示前 i 个数里挑若干个数是否能组成和为 j 

方程 function

dp[i][j] = dp[i - 1][j] or dp[i - 1][j - A[i - 1]] 如果 j >= A[i - 1] 
dp[i][j] = dp[i - 1][j] 如果 j < A[i - 1] 
第 i 个数的下标是 i - 1,所以用的是 A[i - 1] 而不是 A[i] 

初始化 initialization

dp[0][0] = true 
dp[0][1...m] = false 

答案 answer

使得 dp[n][v], 0 s <= v <= m 为 true 的最大 v 

b.多重背包

  • 状态 state
dp[i][j] 表示前i个物品挑出一些放到 j 的背包里的最大价值和 

方程 function

dp[i][j] = max(dp[i - 1][j - count * A[i - 1]] + count * V[i - 1]) 
其中 0 <= count <= j / A[i - 1] 

初始化 initialization

dp[0][0..m] = 0 

答案 answer

dp[n][m]

②区间型

  • 题目中有 subarray / substring 的信息
  • 大区间依赖小区间
    dp[i][j] 表示数组/字符串中 i, j 这一段区间的最优值/可行性/方案总数
  • 状态 state
dp[i][j] 表示数组/字符串中 i,j 这一段区间的最优值/可行性/方案总数 

方程 function

 dp[i][j] = max/min/sum/or(dp[i,j 之内更小的若干区间]) 

③匹配型

  • 通常给出两个字符串
  • 两个字符串的匹配值依赖于两个字符串前缀的匹配值
  • 字符串长度为 n,m 则需要开 (n + 1) x (m + 1) 的状态数组
  • 要初始化 dp[i][0]dp[0][i]
  • 通常都可以用滚动数组进行空间优化
  • 状态 state
dp[i][j] 表示第一个字符串的前 i 个字符与第二个字符串的前 j 个字符怎么样怎么样(max/min/sum/or) 

④划分型

  • 是前缀型动态规划的一种, 有前缀的思想
  • 如果指定了要划分为几个部分:
  • dp[i][j] 表示前i个数/字符划分为j个 部分的最优值/方案数/可行性
  • 如果没有指定划分为几个部分:
  • dp[i] 表示前i个数/字符划分为若干个 部分的最优值/方案数/可行性
  • 状态 state
    指定了要划分为几个部分:dp[i][j] 表示前i个数/字符划分为j个部分的最优值/方案数/可行性
    没有指定划分为几个部分: dp[i] 表示前i个数/字符划分为若干个部分的最优值/方案数/可行性

⑤接龙型

  • 通常会给一个接龙规则,问你最长的龙有多长
  • 状态表示通常为: dp[i] 表示以坐标为 i 的元素结尾的最长龙的长度
  • 方程通常是: dp[i] = max{dp[j] + 1}, j 的后面可以接上 i
  • LIS 的二分做法选择性的掌握,但并不是所有的接龙型DP都可以用二分来优化
  • 状态 state
    状态表示通常为: dp[i] 表示以坐标为 i 的元素结尾的最长龙的长度

方程 function

dp[i] = max{dp[j] + 1}, j 的后面可以接上 i 

复杂度

  • 时间复杂度:
  • O(状态总数 * 每个状态的处理耗费)
  • 等于O(状态总数 * 决策数)
  • 空间复杂度:
  • O(状态总数) (不使用滚动数组优化)
  • O(状态总数 / n)(使用滚动数组优化, n是被滚动掉的那一个维度)

可以来试试这几道领扣例题

差不多就分享到这里啦,像是双指针、排序算法、二叉树、宽度优先搜索、深度优先搜索的使用条件、时间复杂度、代码模板,这份模板也都有涵盖。
在这里插入图片描述
当然啦,学习算法还是要一步步循序渐进,在理解解题思路的情况下去背诵这份模板,这样它才能真正的发挥价值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值