Triangle
题目
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
> [> [2],> [3,4],> [6,5,7],> [4,1,8,3]> ]>>
>
The minimum path sum from top to bottom is
11
(i.e., 2 + 3 + 5 + 1 = 11).
题目是说,从三角形的最上层走到最下层,每次只走到下一层的相邻元素,求从顶点走到最下层的最短路径长度。
方法1:DFS遍历
从上往下深度优先遍历搜索,记录所有情况之中最小值
|
时间复杂度
方法2:分治法
从最底层走到某个点[i,j]的最短路径长度可以分解为两个子问题:
- 这个点自身的路径 长度+下一层左边节点路径长度
- 这个点自身的路径 长度+下一层左右边节点路径长度
最终的结果需要取这两种情况的最小值。
边界条件:最下面一层的最小路径长度是1
|
时间复杂度
方法3:记忆化搜索
显然上面的方法有很多重复计算的值:
|
其中[x+2,y+1]就被重复计算了两次。
可以将这些多次重复计算的值存下来,计算过一次之后后面再用到就可以避免重复计算了。
|
时间复杂度
方法4:多重循环
实现方式1:自底向上
从终点(最下面一层)出发,逐层向上至终点。
状态:f[i,j]表示从最下面一层到点[i,j]最短路径长度
方程:f[i,j] = a[i,j]+min(f[i+1,j],f[i+1,j+1])
初始化:f[i,j] = a[i,j],其中i是最下面一行
答案:f[0,0]
|
实现方式2:自顶向下
从起点(顶点)出发,逐层向下至最后一层。
状态:f[i,j]表示从最顶点到点[i,j]最短路径长度
方程:f[i,j] = a[i,j]+min(f[i-1,j-1],f[i-1,j])
初始化:f[0,0] = a[0,0]
答案:min(f[i,j]),其中i是最下面一层
|
总结一下
什么时候用DP
三个条件满足其一则极有可能是需要用DP求解:
- 求最大、最小值
- 判断是否可行
- 统计方案个数
什么时候不用DP
三个条件满足其一则极不可能用DP:
- 输出所有方案
- 给得是集合,不是序列(元素顺序不可换)
- 暴力算法的时间复杂度已经是多项式复杂度了(n^2,n^3),dp擅长将指数复杂度优化到多相似复杂度
动态规划四要素:
状态:f[][]
的含义,最难!
方程:状态之间的联系,怎么用小状态算大状态
初始化:最小状态是什么,起点
答案:最大状态是什么,终点
两种方法:
- 自顶向下:从起点出发到终点
- 自底向上:从终点出发,反推至起点
VS递归三要素
- 定义(状态)
- 接受了什么参数
- 做了什么事情
- 返回了什么值
- 拆解(方程)
- 符合将参数变小
- 出口(初始化)
- 什么时候可以直接return
坐标型动态规划
Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example 1:
> [[1,3,1],> [1,5,1],> [4,2,1]]>>
>
Given the above grid map, return
> 7>
>
. Because the path 1→3→1→1→1 minimizes the sum.
分析
坐标性动态规划
状态:f[i,j]表示从(0,0)出发走到(i,j)的路径长度
方程:f[i,j] = a[i,j] + min(f[i-1,j],f[i,j-1]),只能从左边和上边走过来
初始化:初始化二维数组时,初始化第0行和第0列
答案:f[end,end]
代码
|
Unique Paths
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?
求从左上角走到右下角的方案个数,到右下角可能从上面或者左边的点过来。
状态:f[i,j]:从(0,0)到(i,j)的方案个数
方程:f[i,j] = f[i-1,j]+f[i,j-1],走到[i,j]有两种方式,从[i-1,j]和从[i,j-1],两种方式方案数加和为走到[i,j]点的总方案数
初始化:第0行和第0列的方案数为1,f[i,0]=f[0,j]=1
结果:f[m,n],右下角元素的状态值
|
Unique Paths II
Follow up for “Unique Paths”:
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as
1
and0
respectively in the grid.For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
> [> [0,0,0],> [0,1,0],> [0,0,0]> ]>>
>
The total number of unique paths is
2
.
在上一题的基础上设置了一些障碍点,所以只需要对障碍点进行判断即可。遇到障碍点时方案数设置为1.
|
Climbing Stairs
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
Example 1:
> Input: 2> Output: 2> Explanation: There are two ways to climb to the top.>> 1. 1 step + 1 step> 2. 2 steps>>
>
Example 2:
> Input: 3> Output: 3> Explanation: There are three ways to climb to the top.>> 1. 1 step + 1 step + 1 step> 2. 1 step + 2 steps> 3. 2 steps + 1 step>
分析
看成是一维数组,从起点走到终点,每次只能走1或2步。
状态:f[i]走到i点的方案数
转移方程:f[i] = f[i-1]+f[i-1],因为只能走一步或者两步,所以只能从前一个或者两个格子过来。
初始化:f[0] = 1;f[1] = 1;f[2] = 2
结果:f[n]
|
Jump Game
动态规划可以做,但是贪心法是最优方法
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A =[2,3,1,1,4]
, returntrue
.A =
[3,2,1,0,4]
, returnfalse
.
分析
数组中的数字表示当前点能够跳跃的最大步长,判断是否可以跳到最后一步:是否有可行方案问题
坐标型动态规划,一维坐标
状态:s[i],是否能从起点跳到i点
取决于前面是否存在点j:
- 从起点是否能跳到j点:s[j]
- 从j是否能跳到i:j+s[j]>=i
转移方程:s[i] = s[j] && j+s[j]>=i(j<i)
初始化:s[0]=1
答案:s[m],最后一个元素的状态
|
时间复杂度:,提交后超时。
贪心法:
两个指针,一个从头向尾移动,另一个计算能够到达的最远距离。
需要注意的是:左侧指针向右移动时不能超过记录最远到达距离的指针。
|
Jump Game II
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A =[2,3,1,1,4]
The minimum number of jumps to reach the last index is
2
. (Jump1
step from index 0 to 1, then3
steps to the last index.)
数组中的数字表示当前点能够跳跃的最大步长,求从起点到终点跳跃最少的方案跳跃次数
求最小,坐标型动态规划
状态:s[i]从起点出发跳到i点需要步数
转移方程:s[i] = min(s[j]+1),j满足条件可以一步跳到i,加个判断
初始化:s[0] = 0
答案:s[m],最后一个元素状态
|
时间复杂度:,提交后超时。
贪心法:
两个指针,一个从头向尾移动,另一个计算能够到达的最远距离。
需要注意的是:左侧指针向右移动时不能超过记录最远到达距离的指针。
|
Longest Increasing Subsequence
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given[10, 9, 2, 5, 3, 7, 101, 18]
,
The longest increasing subsequence is[2, 3, 7, 101]
, therefore the length is4
. Note that there may be more than one LIS combination, it is only necessary for you to return the length.Your algorithm should run in O(n2) complexity.
subqequence:子序列,可以跳着取
substring:子串,相连的,不可以跳着取
思路
DP和二分法
判断是否使用DP:
- 求最长
- 一维序列,元素位置不可交换
- 暴力复杂度是O(2^n)
看成是小人跳木桩,数组的值为木桩的高度,小人每次踩一个更高的木桩
DP
状态:f[i]表示从任意一个木桩出发,从低到高,跳到i点,最多踩过多少个木桩
转移方程:f[i] = max(f[j]+1) j满足:j<i && nums[j]<nums[i]
初始化:f[0] = f[1] = …= f[n-1] = 1 从前面的任何一个点出发跳到此处要经过多少根木桩,初始化时,只经过自己跳到自己踩过的木桩树为1。
结果:max(f[1],f[2],….,f[n-1]) 因为递增子序列不一定以最后一个元素为结尾,这道题要求的是最长的子序列,所以需要在所有的点里面找到最大的值返回。
|
时间复杂度
二分法
|
序列型动态规划
状态:f[i]表示前i个位置/数字/字符,第i个…
方程:f[i] = g(f[j]),j是i前面的位置
初始化:f[0]
结果:f[n]
Word Break
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words.
For example, given
s ="leetcode"
,
dict =["leet", "code"]
.Return true because
"leetcode"
can be segmented as"leet code"
.
给一串字母和单词表,判断是否可以被切分。
|
Palindrome Partitioning II
|
将字符串切分使得每一段都是回文串,求最少要切几刀。
|
双序列型动态规划
给两个序列
状态:f[i,j]表示第一个字符串的前i个,第二个字符串的前j个
转移方程:
初始化:f[i,0],f[0,j]
结果:f[n,m]
例题1:最长公共子串
给出两个字符串,找到最长公共子串,并返回其长度。
样例
给出A=“ABCD”,B=“CBCE”,返回 2
分析:
代码:
|
例题2:最长公共子序列
|
Edit Distance
题目
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)
You have the following 3 operations permitted on a word:
a) Insert a character
b) Delete a character
c) Replace a character
给定两个字符串,最少经过多少次修改可以使第一个字符串和诶二哥字符串一样。
分析
|
代码
|
Distinct Subsequences
题目
Given a string S and a string T, count the number of distinct subsequences of S which equals T.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie,
"ACE"
is a subsequence of"ABCDE"
while"AEC"
is not).Here is an example:
S ="rabbbit"
, T ="rabbit"
Return
3
.
从S中挑出T有多少种方法
分析
|
代码
|
Interleaving String
题目
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 ="aabcc"
,
s2 ="dbbca"
,When s3 =
"aadbbcbcac"
, return true.
When s3 ="aadbbbaccc"
, return false.
三个字符串s1,s2,s3,判断s3是否可以由s1,s2交替组成(顺序不变,交替着选)
分析
|
代码
|