目录
动态规划
斐波那契数列
题目
大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。
斐波那契数列是一个满足 𝑓𝑖𝑏(𝑥)={1𝑥=1,2𝑓𝑖𝑏(𝑥−1)+𝑓𝑖𝑏(𝑥−2)𝑥>2fib(x)={1fib(x−1)+fib(x−2)x=1,2x>2 的数列
数据范围:1≤𝑛≤40
要求:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛),本题也有时间复杂度 𝑂(𝑙𝑜𝑔𝑛)的解法
输入描述:
一个正整数n
返回值描述:
输出一个正整数。
示例1
输入:4
返回值:3
说明:根据斐波那契数列的定义可知,fib(1)=1,fib(2)=1,fib(3)=fib(3-1)+fib(3-2)=2,fib(4)=fib(4-1)+fib(4-2)=3,所以答案为3。
示例2
输入:1
返回值:1
示例3
输入:2
返回值:
1
分析
入门。相当于当前这个是由他前面两个数推导出来的,所以要知道1和2的初始化为多少,然后计算。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @return int整型
*/
public int Fibonacci (int n) {
// write code here
int [] dp=new int[n];
dp[0]=1;
dp[1]=1;
for(int i=2;i<n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n-1];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param n int整型
# @return int整型
#
class Solution:
def Fibonacci(self , n: int) -> int:
# write code here
dp=[1]*n
for i in range(2,n):
dp[i]=dp[i-1]+dp[i-2]
return dp[n-1]
跳台阶
题目
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
数据范围:1≤𝑛≤40
要求:时间复杂度:𝑂(𝑛),空间复杂度: 𝑂(1)
示例1
输入:2
返回值:2
说明:青蛙要跳上两级台阶有两种跳法,分别是:先跳一级,再跳一级或者直接跳两级。因此答案为2
示例2
输入:7
返回值:21
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param number int整型
* @return int整型
*/
public int jumpFloor (int number) {
// write code here
int [] dp=new int[number+1];
dp[0]=1;
dp[1]=1;
for(int i=2;i<=number;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[number];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param number int整型
# @return int整型
#
class Solution:
def jumpFloor(self , number: int) -> int:
# write code here
dp=[0]*(number+1)
dp[0]=1
dp[1]=1
for i in range(2,number+1):
dp[i]=dp[i-1]+dp[i-2]
return dp[number]
最小花费爬楼梯
题目
给定一个整数数组 𝑐𝑜𝑠𝑡,其中 𝑐𝑜𝑠𝑡[𝑖] 是从楼梯第𝑖 个台阶向上爬需要支付的费用,下标从0开始。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
数据范围:数组长度满足 1≤𝑛≤105 ,数组中的值满足 1≤𝑐𝑜𝑠𝑡𝑖≤104
示例1
输入:[2,5,20]
返回值:5
说明:你将从下标为1的台阶开始,支付5 ,向上爬两个台阶,到达楼梯顶部。总花费为5
示例2
输入:[1,100,1,1,1,90,1,1,80,1]
返回值:6
说明:
你将从下标为 0 的台阶开始。
1.支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
2.支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
3.支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
4.支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
5.支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
6.支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。
分析
dp[i]所表示的含义是到达第i个台阶所花费的最小费用,所以他说可以从第0个开始或者第一个开始,dp[0]和dp[1]的初始化为0,然后到达第i个台阶可以是到达前一个台阶总花费+那个台阶的消耗或者前两个台阶总花费---+那个台阶的消耗,取最小值
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param cost int整型一维数组
* @return int整型
*/
public int minCostClimbingStairs (int[] cost) {
// write code here
int [] dp=new int[cost.length+1];
dp[0]=0;
dp[1]=0;
for(int i=2;i<=cost.length;i++){
dp[i]=Math.min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1]);
}
return dp[cost.length];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param cost int整型一维数组
# @return int整型
#
class Solution:
def minCostClimbingStairs(self , cost: List[int]) -> int:
# write code here
dp=[0]*(len(cost)+1)
for i in range(2,len(cost)+1):
dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
return dp[len(cost)]
最长公共子序列(二)
题目
给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列
数据范围:0≤∣𝑠𝑡𝑟1∣,∣𝑠𝑡𝑟2∣≤2000
要求:空间复杂度 𝑂(𝑛2),时间复杂度 𝑂(𝑛2)
示例1
输入:"1A2C3D4B56","B1D23A456A"
返回值:"123456"
示例2
输入:"abc","def"
返回值:"-1"
示例3
输入:"abc","abc"
返回值:"abc"
示例4
输入:"ab",""
返回值:"-1"
分析
dp[i][j]用来表示到s1的i-1位置和s2的j-1位置的最长公共子序列,当i-1和j-1位置上字母一样的时候,直接在前一个的基础上+1,不一样的时候看舍弃哪个会更长一点
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* longest common subsequence
* @param s1 string字符串 the string
* @param s2 string字符串 the string
* @return string字符串
*/
public String LCS (String s1, String s2) {
// write code here
int [][] dp=new int [s1.length()+1][s2.length()+1];
dp[0][0]=0;
for(int i=1;i<=s1.length();i++){
for(int j=1;j<=s2.length();j++){
if(s1.charAt(i-1)==s2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1]+1;
}else{
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
if(dp[s1.length()][s2.length()]==0){
return "-1";
}
StringBuilder sb=new StringBuilder();
for(int i=s1.length(),j=s2.length();i>0 && j>0;){
if(s1.charAt(i-1)==s2.charAt(j-1)){
sb.append(s1.charAt(i-1));
i--;
j--;
}else if(dp[i-1][j]>dp[i][j-1]){
i--;
}else{
j--;
}
}
return sb.reverse().toString();
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# longest common subsequence
# @param s1 string字符串 the string
# @param s2 string字符串 the string
# @return string字符串
#
class Solution:
def LCS(self , s1: str, s2: str) -> str:
# write code here
m=len(s1)
n=len(s2)
dp=[[0] * (n+1) for _ in range(m+1)]
for i in range(1,m+1):
for j in range(1,n+1):
if s1[i-1]==s2[j-1]:
dp[i][j]=dp[i-1][j-1]+1
else:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
if dp[m][n]==0:
return "-1"
res=[]
i, j = m, n
while i > 0 and j > 0:
if s1[i-1] == s2[j-1]:
res.append(s1[i-1])
i -= 1
j -= 1
elif dp[i-1][j] > dp[i][j-1]:
i -= 1
else:
j -= 1
return ''.join(reversed(res))
最长公共子串
题目
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
数据范围: 1≤∣𝑠𝑡𝑟1∣,∣𝑠𝑡𝑟2∣≤5000
要求: 空间复杂度 𝑂(𝑛2),时间复杂度 𝑂(𝑛2)
示例1
输入:"1AB2345CD","12345EF"
返回值:"2345"
备注:1≤∣𝑠𝑡𝑟1∣,∣𝑠𝑡𝑟2∣≤5 0001≤∣str1∣,∣str2∣≤5000
分析
这道题和上一道题不一样的地方在于,这个公共子串必须是连续的,就是说下标必须连续。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
public String LCS (String str1, String str2) {
// write code here
int n=str1.length();
int m=str2.length();
int [][] dp=new int[n+1][m+1];
dp[0][0]=0;
int max=0;
int index=0;
for(int i=1;i<=str1.length();i++){
for(int j=1;j<=str2.length();j++){
if(str1.charAt(i-1)==str2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1]+1;
if(dp[i][j]>max){
max=dp[i][j];
index=i;
}
}else{
dp[i][j]=0;
}
}
}
if(max == 0) return "-1";
return str1.substring(index-max, index);
}
}
python
python
class Solution:
def LCS(self, str1: str, str2: str) -> str:
max_len = 0
res = ""
# 枚举所有可能的子串,利用 Python 字符串 in 优化(底层C速度)
for i in range(len(str1)):
for j in range(i + max_len + 1, len(str1) + 1):
substr = str1[i:j]
if substr in str2:
max_len = j - i
res = substr
else:
break
return res if res else "-1"
不同路径的数目(一)
题目
一个机器人在m×n大小的地图的左上角(起点)。
机器人每次可以向下或向右移动。机器人要到达地图的右下角(终点)。
可以有多少种不同的路径从起点走到终点?

备注:m和n小于等于100,并保证计算结果在int范围内
数据范围:0<𝑛,𝑚≤100,保证计算结果在32位整型范围内
要求:空间复杂度 𝑂(𝑛𝑚),时间复杂度 𝑂(𝑛𝑚)
进阶:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑚𝑖𝑛(𝑛,𝑚))
示例1
输入:2,1
返回值:1
示例2
输入:2,2
返回值:2
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param m int整型
* @param n int整型
* @return int整型
*/
public int uniquePaths (int m, int n) {
// write code here
int [][]dp=new int[m+1][n+1];
for(int i=1;i<=m;i++){
dp[i][1]=1;
}
for(int j=1;j<=n;j++){
dp[1][j]=1;
}
for(int i=2;i<=m;i++){
for(int j=2;j<=n;j++){
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m][n];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param m int整型
# @param n int整型
# @return int整型
#
class Solution:
def uniquePaths(self , m: int, n: int) -> int:
# write code here
dp=[[0] * n for _ in range(m)]
for i in range(m):
dp[i][0]=1
for j in range(n):
dp[0][j]=1
for i in range(1,m):
for j in range(1,n):
dp[i][j]=dp[i-1][j]+dp[i][j-1]
return dp[m-1][n-1]
矩阵的最小路径和
题目
给定一个 n * m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
数据范围: 1≤𝑛,𝑚≤500,矩阵中任意值都满足 0≤𝑎𝑖,𝑗≤100
要求:时间复杂度 𝑂(𝑛𝑚)
例如:当输入[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]时,对应的返回值为12,
所选择的最小累加和路径如下图所示:

示例1
输入:[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
返回值:12
示例2
输入:[[1,2,3],[1,2,3]]
返回值:7
备注:
1≤𝑛,𝑚≤20001≤n,m≤2000
1≤𝑎𝑖,𝑗≤1001≤ai,j≤100
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param matrix int整型二维数组 the matrix
* @return int整型
*/
public int minPathSum (int[][] matrix) {
// write code here
int n=matrix.length;
int m=matrix[0].length;
int [][] dp=new int[n][m];
dp[0][0]=matrix[0][0];
for(int i=1;i<n;i++){
dp[i][0]=dp[i-1][0]+matrix[i][0];
}
for(int j=1;j<m;j++){
dp[0][j]=dp[0][j-1]+matrix[0][j];
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+matrix[i][j];
}
}
return dp[n-1][m-1];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param matrix int整型二维数组 the matrix
# @return int整型
#
class Solution:
def minPathSum(self , matrix: List[List[int]]) -> int:
# write code here
n=len(matrix)
m=len(matrix[0])
dp=[[0] * m for _ in range(n)]
dp[0][0]=matrix[0][0]
for i in range(1,n):
dp[i][0]=dp[i-1][0]+matrix[i][0]
for j in range(1,m):
dp[0][j]=dp[0][j-1]+matrix[0][j]
for i in range(1,n):
for j in range(1,m):
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+matrix[i][j]
return dp[n-1][m-1]
把数字翻译成字符串
题目
有一种将字母编码成数字的方式:'a'->1, 'b->2', ... , 'z->26'。
现在给一串数字,返回有多少种可能的译码结果
数据范围:字符串长度满足 0<𝑛≤90
进阶:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛)
示例1
输入:"12"
返回值:2
说明:2种可能的译码结果("ab" 或"l")
示例2
输入:"31717126241541717"
返回值:192
说明:192种可能的译码结果
分析
dp表示译码的方法。
首先初始化,把特殊情况现在前面讨论了,然后第一个数字的方法只有1种,然后带上第2位,如果第一位和第二位组合在一起小于26且第二位不是0的话,那么译码方法是2,不然就是1,为什么要单独说一下第二位是不是0呢?因为如果是0的话,第二位是不能单独译码的,智能和第一位一起,所以只有一种译码方法
分为以下几种情况:
1.当前数字是0,但是前一位是1或者2,那么当前必须和之前一位一起译码,相当于把他们两个绑定了,所以是dp[i]=dp[i-2](要往前走两位)(而且一定要记住dp数组的含义是译码方法,所以不加一)
2.如果当前数字小于等于6并且前一位的数字是1或者2,那么就是正常的,dp[i]=dp[i-1]+dp[i-2],不
3.其他情况 不能组合,只能单独解码,dp[i]=dp[i-1]
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 解码
* @param nums string字符串 数字串
* @return int整型
*/
public int solve (String nums) {
// write code here
if(nums.length() == 0 || nums.charAt(0) == '0') return 0;
if(nums.length()==1) return 1;
int [] dp=new int[nums.length()];
dp[0]=1;
int two= (nums.charAt(0)-'0')*10 + (nums.charAt(1)-'0');
dp[1]=(two>=1 && two<=26 && nums.charAt(1) != '0')?2:1;
for(int i=2;i<nums.length();i++){
if(nums.charAt(i)=='0'){
if(nums.charAt(i-1)=='1' || nums.charAt(i-1)=='2'){
dp[i]=dp[i-2];
}else{
dp[i]=0;
}
}else if(nums.charAt(i-1)=='1' || nums.charAt(i-1)=='2' && nums.charAt(i)<='6'){
dp[i]=dp[i-1]+dp[i-2];
}else{
dp[i]=dp[i-1];
}
}
return dp[nums.length()-1];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 解码
# @param nums string字符串 数字串
# @return int整型
#
class Solution:
def solve(self , nums: str) -> int:
# write code here
if len(nums)==0 or nums[0]=='0':
return 0
n=len(nums)
if n==1:
return 1
dp=[0]*n
dp[0]=1
two = int(nums[0]) * 10 + int(nums[1])
dp[1]=2 if(two<=26 and nums[1]!='0') else 1
for i in range(2,n):
if nums[i]=='0':
if nums[i-1]=='1' or nums[i-1]=='2':
dp[i]=dp[i-2]
else:
dp[i]=0
elif nums[i-1]=='1' or nums[i-1]=='2' and nums[i]<='6':
dp[i]=dp[i-1]+dp[i-2]
else:
dp[i]=dp[i-1]
return dp[n-1]
兑换零钱(一)
题目
给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。
如果无解,请返回-1.
数据范围:数组大小满足 0≤𝑛≤10000, 数组中每个数字都满足 0<𝑣𝑎𝑙≤10000,0≤𝑎𝑖𝑚≤5000
要求:时间复杂度 𝑂(𝑛×𝑎𝑖𝑚) ,空间复杂度 𝑂(𝑎𝑖𝑚)。
示例1
输入:[5,2,3],20
返回值:4
示例2
输入:[5,2,3],0
返回值:0
示例3
输入:[3,5],2
返回值:-1
备注:0≤𝑛≤10 0000≤n≤10000 0≤𝑎𝑖𝑚≤5 0000≤aim≤5000
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 最少货币数
* @param arr int整型一维数组 the array
* @param aim int整型 the target
* @return int整型
*/
public int minMoney (int[] arr, int aim) {
// write code here
int [][] dp=new int[arr.length][aim+1];
if(aim == 0) return 0;
if(arr.length==0){
return -1;
}
for(int i=0;i<=aim;i++){
dp[0][i]=aim+1;
}
for(int i=arr[0];i<=aim;i+=arr[0]){
dp[0][i]=i/arr[0];
}
dp[0][0]=0;
for(int i=1;i<arr.length;i++){
for(int j=0;j<=aim;j++){
dp[i][j]=dp[i-1][j];
if(j>=arr[i] && dp[i][j-arr[i]]!=aim+1){
dp[i][j]=Math.min(dp[i][j],dp[i][j-arr[i]]+1);
}
}
}
return dp[arr.length-1][aim] == aim+1 ? -1 : dp[arr.length-1][aim];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 最少货币数
# @param arr int整型一维数组 the array
# @param aim int整型 the target
# @return int整型
#
class Solution:
def minMoney(self , arr: List[int], aim: int) -> int:
# write code here
if aim == 0:
return 0
if not arr:
return -1
a=aim+1
dp=[[a] * (aim+1) for _ in range(len(arr))]
dp[0][0]=0
for i in range(arr[0],aim+1,arr[0]):
dp[0][i]=i//arr[0]
for i in range(1,len(arr)):
for j in range(aim+1):
dp[i][j] = dp[i-1][j] # 不选当前硬币
if j >= arr[i] and dp[i][j - arr[i]] != a:
dp[i][j] = min(dp[i][j], dp[i][j - arr[i]] + 1)
return dp[-1][aim] if dp[-1][aim] != a else -1
最长上升子序列(一)
题目
给定一个长度为 n 的数组 arr,求它的最长严格上升子序列的长度。
所谓子序列,指一个数组删掉一些数(也可以不删)之后,形成的新数组。例如 [1,5,3,7,3] 数组,其子序列有:[1,3,3]、[7] 等。但 [1,6]、[1,3,5] 则不是它的子序列。
我们定义一个序列是 严格上升 的,当且仅当该序列不存在两个下标 𝑖i 和 𝑗j 满足 𝑖<𝑗i<j 且 𝑎𝑟𝑟𝑖≥𝑎𝑟𝑟𝑗arri≥arrj。
数据范围: 0≤𝑛≤1000
要求:时间复杂度 𝑂(𝑛2), 空间复杂度 𝑂(𝑛)
示例1
输入:[6,3,1,5,2,3,7]
返回值:4
说明:该数组最长上升子序列为 [1,2,3,7] ,长度为4
分析
每一个单独的数字都可以看作是上升子序列,所以初始化都为1
dp[i] 的定义是:以第 i 个数结尾的最长严格上升子序列长度
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 给定数组的最长严格上升子序列的长度。
* @param arr int整型一维数组 给定的数组
* @return int整型
*/
public int LIS (int[] arr) {
// write code here
if(arr.length==1){
return 1;
}
if(arr.length==0){
return 0;
}
int res=0;
int [] dp=new int[arr.length];
Arrays.fill(dp,1);
for(int i=1;i<arr.length;i++){
for(int j=0;j<i;j++){
if(arr[j]<arr[i]){
dp[i]=Math.max(dp[j]+1,dp[i]);
}
}res=Math.max(res,dp[i]);
}
return res;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 给定数组的最长严格上升子序列的长度。
# @param arr int整型一维数组 给定的数组
# @return int整型
#
class Solution:
def LIS(self , arr: List[int]) -> int:
# write code here
if len(arr)==0:
return 0
if len(arr)==1:
return 1
dp=[1]*len(arr)
result=0
for i in range(1,len(arr)):
for j in range(i):
if arr[j]<arr[i]:
dp[i]=max(dp[j]+1,dp[i])
result=max(result,dp[i])
return result
连续子数组的最大和
题目
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1。求所有子数组的和的最大值。
数据范围:
1<=𝑛<=2×105
−100<=𝑎[𝑖]<=100
要求:时间复杂度为 𝑂(𝑛),空间复杂度为 𝑂(𝑛)
进阶:时间复杂度为 𝑂(𝑛),空间复杂度为 𝑂(1)
示例1
输入:[1,-2,3,10,-4,7,2,-5]
返回值:18
说明:经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18
示例2
输入:[2]
返回值:2
示例3
输入:[-10]
返回值:-10
分析
当累计的和小于1 的时候,再继续加下去只会使得后面的数字更小,所以我们可以从这里断开,重新开始
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型一维数组
* @return int整型
*/
public int FindGreatestSumOfSubArray (int[] array) {
// write code here
if(array.length==0){
return 0;
}
if(array.length==1){
return array[0];
}
int [] dp=new int[array.length];
dp[0]=array[0];
int result=array[0];
for(int i=1;i<array.length;i++){
dp[i]=Math.max(array[i],dp[i-1]+array[i]);
result=Math.max(result,dp[i]);
}
return result;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param array int整型一维数组
# @return int整型
#
class Solution:
def FindGreatestSumOfSubArray(self , array: List[int]) -> int:
# write code here
dp=[0]*len(array)
dp[0]=array[0]
result=dp[0]
for i in range(1,len(array)):
dp[i]=max(dp[i-1]+array[i],array[i])
result=max(result,dp[i])
return result
最长回文字串
题目
对于长度为n的一个字符串A(仅包含数字,大小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度。
数据范围: 1≤𝑛≤1000
要求:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛2)
进阶: 空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛)
示例1
输入:"ababc"
返回值:3
说明:最长的回文子串为"aba"与"bab",长度都为3
示例2
输入:"abbba"
返回值:5
示例3
输入:"b"
返回值:1
分析
dp[i][j]:表示:字符串从下标 i 到 j 的这一段,是不是回文
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param A string字符串
* @return int整型
*/
public int getLongestPalindrome (String A) {
// write code here
int n=A.length();
int result=0;
boolean [][] dp=new boolean[n][n];
for(int i=n-1;i>=0;i--){
for(int j=i;j<n;j++){
if(A.charAt(i)==A.charAt(j)){
if(j-i<=1){
dp[i][j]=true;
}else if(dp[i+1][j-1]){
dp[i][j]=true;
}
}
if(dp[i][j]){
result=Math.max(result,j-i+1);
}
}
}
return result;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param A string字符串
# @return int整型
#
class Solution:
def getLongestPalindrome(self , A: str) -> int:
# write code here
n=len(A)
dp=[[False] * n for _ in range(n)]
result=0
for i in range(n-1,-1,-1):
for j in range(i,n):
if A[i]==A[j]:
if j-i<=1:
dp[i][j]=True
elif dp[i+1][j-1]:
dp[i][j]=True
if dp[i][j]:
result=max(result,j-i+1)
return result
数字字符串转化为IP地址
题目
现在有一个只包含数字的字符串,将该字符串转化成IP地址的形式,返回所有可能的情况。
例如:
给出的字符串为"25525522135",
返回["255.255.22.135", "255.255.221.35"]. (顺序没有关系)
数据范围:字符串长度 0≤𝑛≤12
要求:空间复杂度 𝑂(𝑛!),时间复杂度 𝑂(𝑛!)
注意:ip地址是由四段数字组成的数字序列,格式如 "x.x.x.x",其中 x 的范围应当是 [0,255]。
示例1
输入:"25525522135"
返回值:["255.255.22.135","255.255.221.35"]
示例2
输入:"1111"
返回值:["1.1.1.1"]
示例3
输入:"000256"
返回值:[]
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return string字符串ArrayList
*/
ArrayList<String> result=new ArrayList<>();
public ArrayList<String> restoreIpAddresses (String s) {
// write code here
int n=s.length();
if(n<=3 || n>12){
return result;
}
back(s,0,0);
return result;
}
public void back(String s,int start,int num){
if(num==3){
if(isValid(s,start,s.length()-1)){
result.add(s);
}
return;
}
for(int i=start;i<s.length();i++){
if(isValid(s,start,i)){
s=s.substring(0,i+1)+'.'+s.substring(i+1);
num++;
back(s,i+2,num);
num--;
s = s.substring(0, i + 1) + s.substring(i + 2);
}else{
break;
}
}
}
public boolean isValid(String s,int start,int end){
if(end<start){
return false;
}
if(s.charAt(start)=='0' && start!=end){
return false;
}
int num=0;
for(int i=start;i<=end;i++){
if(s.charAt(i)>'9' || s.charAt(i)<'0'){
return false;
}
num=num*10+(s.charAt(i)-'0');
if(num>255){
return false;
}
}
return true;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# @param s string字符串
# @return string字符串一维数组
#
from typing import List
class Solution:
def __init__(self):
self.result=[]
def restoreIpAddresses(self , s: str) -> List[str]:
# write code here
if len(s)<4 or len(s)>12:
return self.result
self.back(s,0,0)
return self.result
def back(self,s,start,sum):
if sum == 3:
if self.isValid(s, start, len(s)-1):
self.result.append(s)
return
# 循环切分
for i in range(start, len(s)):
if self.isValid(s, start, i):
# 插入小数点
new_s = s[:i+1] + "." + s[i+1:]
sum += 1
self.back(new_s, i+2, sum)
# 回溯
sum -= 1
else:
break
def isValid(self,s,start,end):
if start>end:
return False
if s[start]=='0' and end!=start:
return False
num = 0
for i in range(start,end+1):
if not s[i].isdigit():
return False
num = num * 10 + int(s[i])
if num > 255:
return False
return True
编辑距离(一)
题目
给定两个字符串 str1 和 str2 ,请你算出将 str1 转为 str2 的最少操作数。
你可以对字符串进行3种操作:
1.插入一个字符
2.删除一个字符
3.修改一个字符。
字符串长度满足 1≤𝑛≤1000 ,保证字符串中只出现小写英文字母。
示例1
输入:"nowcoder","new"
返回值:6
说明:"nowcoder"=>"newcoder"(将'o'替换为'e'),修改操作1次 "nowcoder"=>"new"(删除"coder"),删除操作5次
示例2
输入:"intention","execution"
返回值:5
说明:一种方案为: 因为2个长度都是9,后面的4个后缀的长度都为"tion",于是从"inten"到"execu"逐个修改即可
示例3
输入:"now","nowcoder"
返回值:5
分析
dp[i-1][j] + 1
代表:删除 str1 的最后一个字符
dp[i][j-1] + 1
代表:在 str1 末尾插入一个字符
dp[i-1][j-1] + 1
代表:把 str1 的字符替换成 str2 的字符
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str1 string字符串
* @param str2 string字符串
* @return int整型
*/
public int editDistance (String str1, String str2) {
// write code here
int n=str1.length();
int m=str2.length();
int [][] dp=new int[n+1][m+1];
for(int i=0;i<=n;i++){
dp[i][0]=i;
}
for(int j=0;j<=m;j++){
dp[0][j]=j;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(str1.charAt(i-1)==str2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=Math.min(Math.min(dp[i-1][j]+1,dp[i][j-1]+1),dp[i-1][j-1]+1);
}
}
}
return dp[n][m];
}
}
python
python
from re import I
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param str1 string字符串
# @param str2 string字符串
# @return int整型
#
class Solution:
def editDistance(self , str1: str, str2: str) -> int:
# write code here
n=len(str1)
m=len(str2)
dp=[[0] * (m+1) for _ in range(n+1)]
for i in range(n+1):
dp[i][0]=i
for j in range(m+1):
dp[0][j]=j
for i in range(1,n+1):
for j in range(1,m+1):
if str1[i-1]==str2[j-1]:
dp[i][j]=dp[i-1][j-1]
else:
dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+1)
return dp[n][m]
正则表达式匹配(11)
题目
请实现一个函数用来匹配包括'.'和'*'的正则表达式。
1.模式中的字符'.'表示任意一个字符
2.模式中的字符'*'表示它前面的字符可以出现任意次(包含0次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
数据范围:
1.str 只包含从 a-z 的小写字母。
2.pattern 只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。
-
0≤𝑠𝑡𝑟.𝑙𝑒𝑛𝑔𝑡ℎ≤26
-
0≤𝑝𝑎𝑡𝑡𝑒𝑟𝑛.𝑙𝑒𝑛𝑔𝑡ℎ≤26
示例1
输入:"aaa","a*a"
返回值:true
说明:中间的*可以出现任意次的a,所以可以出现1次a,能匹配上
示例2
输入:"aad","c*a*d"
返回值:true
说明:因为这里 c 为 0 个,a被重复一次, * 表示零个或多个a。因此可以匹配字符串 "aad"。
示例3
输入:"a",".*"
返回值:true
说明:".*" 表示可匹配零个或多个('*')任意字符('.')
示例4
输入:"aaab","a*a*a*c"
返回值:false
分析
match1 = False
if str[i-1] == pattern[j-2] or pattern[j-2] == '.':
match1 = dp[i-1][j]
这里的意思是*可以匹配多次,那么我就一直缩小str,看*前面的数字是否可以持续匹配上,也就是匹配多次的情况
代码
java
java
import java.util.*;
public class Solution {
public boolean match (String str, String pattern) {
int n = str.length();
int m = pattern.length();
boolean[][] dp = new boolean[n+1][m+1];
// 空串匹配空串 为真
dp[0][0] = true;
// 处理:str为空,pattern是 a* / a*b* 这种情况(必须初始化)
for (int j = 1; j <= m; j++) {
if (pattern.charAt(j-1) == '*') {
dp[0][j] = dp[0][j-2];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// 情况1:当前不是 * → 必须和前一个状态同时满足
if (pattern.charAt(j-1) != '*') {
if (dp[i-1][j-1] &&
(str.charAt(i-1) == pattern.charAt(j-1) || pattern.charAt(j-1) == '.')) {
dp[i][j] = true;
}
}
// 情况2:当前是 * → 核心难点
else {
// 两种大情况:* 匹配 0 次 OR 匹配 至少1次
// ① 匹配 0 次:直接忽略 x*
boolean match0 = dp[i][j-2];
// ② 匹配 至少1次:前面字符匹配,且 i-1 位置合法
boolean match1 = false;
if (str.charAt(i-1) == pattern.charAt(j-2) || pattern.charAt(j-2) == '.') {
match1 = dp[i-1][j];
}
dp[i][j] = match0 || match1;
}
}
}
return dp[n][m];
}
}
python
python
class Solution:
def match(self , str: str, pattern: str) -> bool:
n = len(str)
m = len(pattern)
# dp[i][j] 表示 str前i个字符 和 pattern前j个字符 是否匹配
dp = [[False] * (m + 1) for _ in range(n + 1)]
# 空串匹配空串,一定成功
dp[0][0] = True
# 处理:str为空,pattern是 a* / .* / a*b* 这种情况
for j in range(1, m + 1):
if pattern[j-1] == '*':
dp[0][j] = dp[0][j-2]
# 开始填表
for i in range(1, n + 1):
for j in range(1, m + 1):
# 情况1:当前不是 *
if pattern[j-1] != '*':
# 字符相等 或者 是. 并且 前面匹配
if dp[i-1][j-1] and (str[i-1] == pattern[j-1] or pattern[j-1] == '.'):
dp[i][j] = True
# 情况2:当前是 * ------ 核心!
else:
# 选择1:* 匹配 0 次,直接忽略 x*
match0 = dp[i][j-2]
# 选择2:* 匹配至少 1 次
match1 = False
if str[i-1] == pattern[j-2] or pattern[j-2] == '.':
match1 = dp[i-1][j]
# 两种选择只要一个成立就行
dp[i][j] = match0 or match1
return dp[n][m]
最长的括号字串
题目
给出一个长度为 n 的,仅包含字符 '(' 和 ')' 的字符串,计算最长的格式正确的括号子串的长度。
例1: 对于字符串 "(()" 来说,最长的格式正确的子串是 "()" ,长度为 2 .
例2:对于字符串 ")()())" , 来说, 最长的格式正确的子串是 "()()" ,长度为 4 .
字符串长度:0≤𝑛≤5∗105
要求时间复杂度 𝑂(𝑛),空间复杂度 𝑂(𝑛)
示例1
输入:"(()"
返回值:2
示例2
输入:"(())"
返回值:4
分析
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return int整型
*/
public int longestValidParentheses (String s) {
// write code here
int n=s.length();
int [] dp=new int[n];
int result=0;
for(int i=0;i<s.length();i++){
if(i>0 && s.charAt(i)==')'){
if(s.charAt(i-1)=='('){
dp[i]=(i-2>=0?dp[i-2]+2:2);
}else if(s.charAt(i-1)==')' && i-dp[i-1]-1>=0 && s.charAt(i-dp[i-1]-1)=='('){
dp[i]=dp[i-1]+2+(i-dp[i-1]-2>=0?dp[i-dp[i-1]-2]:0);
}
}
result=Math.max(result,dp[i]);
}
return result;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param s string字符串
# @return int整型
#
class Solution:
def longestValidParentheses(self , s: str) -> int:
# write code here
n=len(s)
dp=[0]*n
res=0
for i in range(n):
if i>0 and s[i]==')':
if s[i-1]=='(':
dp[i]=dp[i-2]+2 if i >= 2 else 2
elif s[i-1]==')' and i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=='(':
dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2]//它所对应的左括号的左边的位置
if dp[i]>res:
res=dp[i]
return res
打家劫舍(一)
题目
你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家;如果偷了第二家,那么就不能偷第一家和第三家。
给定一个整数数组nums,数组中的元素表示每个房间存有的现金数额,请你计算在不被发现的前提下最多的偷窃金额。
数据范围:数组长度满足 1≤𝑛≤2×105 ,数组中每个值满足 1≤𝑛𝑢𝑚[𝑖]≤5000
示例1
输入:[1,2,3,4]
返回值:6
说明:最优方案是偷第 2,4 个房间
示例2
输入:[1,3,6]
返回值:7
说明:最优方案是偷第 1,3个房间
示例3
输入:[2,10,5]
返回值:10
说明:最优方案是偷第 2 个房间
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int rob (int[] nums) {
// write code here
if(nums.length==1){
return nums[0];
}
int [] dp=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(dp[0],nums[1]);
for(int i=2;i<nums.length;i++){
dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[nums.length-1];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型
#
class Solution:
def rob(self , nums: List[int]) -> int:
# write code here
if len(nums)==1:
return nums[0]
dp=[0]*len(nums)
dp[0]=nums[0]
dp[1]=max(nums[0],nums[1])
for i in range(2,len(nums)):
dp[i]=max(dp[i-2]+nums[i],dp[i-1])
return dp[len(nums)-1]
打家劫舍(二)
题目
你是一个经验丰富的小偷,准备偷沿湖的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家,如果偷了第二家,那么就不能偷第一家和第三家。沿湖的房间组成一个闭合的圆形,即第一个房间和最后一个房间视为相邻。
给定一个长度为n的整数数组nums,数组中的元素表示每个房间存有的现金数额,请你计算在不被发现的前提下最多的偷窃金额。
数据范围:数组长度满足 1≤𝑛≤2×105,数组中每个值满足 1≤𝑛𝑢𝑚𝑠[𝑖]≤5000
示例1
输入:[1,2,3,4]
返回值:6
说明:最优方案是偷第 2 4 个房间
示例2
输入:[1,3,6]
返回值:6
说明:由于 1 和 3 是相邻的,因此最优方案是偷第 3 个房间
分析
rob1中的函z相当于当前天最多投多少钱,y相当于前一天,x相当于后一天
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int rob (int[] nums) {
// write code here
if(nums.length==1){
return nums[0];
}
if(nums.length==0){
return 0;
}
return Math.max(rob1(nums,0,nums.length-1),rob1(nums,1,nums.length));
}
public int rob1(int [] nums,int start,int end){
int x=0,y=0,z=0;
for(int i=start;i<end;i++){
y=z;
z=Math.max(x+nums[i],y);
x=y;
}
return z;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型
#
class Solution:
def rob(self , nums: List[int]) -> int:
# write code here
if len(nums)==0:
return 0
if len(nums)==1:
return nums[0]
return max(self.rob1(nums,0,len(nums)-1),self.rob1(nums,1,len(nums)))
def rob1(self,nums,start,end):
x=0
y=0
z=0
for i in range(start,end):
y=z
z=max(y,x+nums[i])
x=y
return z
买股票的最好时机(一)
题目
假设你有一个数组prices,长度为n,其中prices[i]是股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
1.你可以买入一次股票和卖出一次股票,并非每天都可以买入或卖出一次,总共只能买入和卖出一次,且买入必须在卖出的前面的某一天
2.如果不能获取到任何利润,请返回0
3.假设买入卖出均无手续费
数据范围: 0≤𝑛≤105,0≤𝑣𝑎𝑙≤104
要求:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)
示例1
输入:[8,9,2,5,4,7,1]
返回值:5
说明:在第3天(股票价格 = 2)的时候买入,在第6天(股票价格 = 7)的时候卖出,最大利润 = 7-2 = 5 ,不能选择在第2天买入,第3天卖出,这样就亏损7了;同时,你也不能在买入前卖出股票。
示例2
输入:[2,4,1]
返回值:2
示例3
输入:[3,2,1]
返回值:0
分析
dp[i][0]代表第i天持有股票
dp[i][1]代表第i天不持有股票
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param prices int整型一维数组
* @return int整型
*/
public int maxProfit (int[] prices) {
// write code here
int [][] dp=new int[prices.length][2];
dp[0][0]=-prices[0];
dp[0][1]=0;
for(int i=1;i<prices.length;i++){
dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
}
return dp[prices.length-1][1];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param prices int整型一维数组
# @return int整型
#
class Solution:
def maxProfit(self , prices: List[int]) -> int:
# write code here
dp=[[0] * 2 for _ in range(len(prices))]
dp[0][0]=-prices[0]
dp[0][1]=0
for i in range(1,len(prices)):
dp[i][0]=max(dp[i-1][0],-prices[i])
dp[i][1]=max(dp[i-1][0]+prices[i],dp[i-1][1])
return dp[len(prices)-1][1]
买股票的最好时机(二)
题目
假设你有一个数组prices,长度为n,其中prices[i]是某只股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
-
你可以多次买卖该只股票,但是再次购买前必须卖出之前的股票
-
如果不能获取收益,请返回0
-
假设买入卖出均无手续费
数据范围: 1≤𝑛≤1×105, 1≤𝑝𝑟𝑖𝑐𝑒𝑠[𝑖]≤104
要求:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛)
进阶:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)
示例1
输入:[8,9,2,5,4,7,1]
返回值:7
说明:在第1天(股票价格=8)买入,第2天(股票价格=9)卖出,获利9-8=1 在第3天(股票价格=2)买入,第4天(股票价格=5)卖出,获利5-2=3 在第5天(股票价格=4)买入,第6天(股票价格=7)卖出,获利7-4=3 总获利1+3+3=7,返回7
示例2
输入:[5,4,3,2,1]
返回值:0
说明:由于每天股票都在跌,因此不进行任何交易最优。最大收益为0。
示例3
输入:[1,2,3,4,5]
返回值:4
说明:第一天买进,最后一天卖出最优。中间的当天买进当天卖出不影响最终结果。最大收益为4。
备注:总天数不大于200000。保证股票每一天的价格在[1,100]范围内。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算最大收益
* @param prices int整型一维数组 股票每一天的价格
* @return int整型
*/
public int maxProfit (int[] prices) {
// write code here
int [][] dp=new int[prices.length][2];
dp[0][0]=-prices[0];
dp[0][1]=0;
for(int i=1;i<prices.length;i++){
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]-prices[i]);
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
}
return dp[prices.length-1][1];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 计算最大收益
# @param prices int整型一维数组 股票每一天的价格
# @return int整型
#
class Solution:
def maxProfit(self , prices: List[int]) -> int:
# write code here
dp=[[0] * 2 for _ in range(len(prices))]
dp[0][0]=-prices[0]
dp[0][1]=0
for i in range(1,len(prices)):
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i])
dp[i][1]=max(dp[i-1][0]+prices[i],dp[i-1][1])
return dp[len(prices)-1][1]
买股票的最好时机(三)
题目
假设你有一个数组prices,长度为n,其中prices[i]是某只股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
-
你最多可以对该股票有两笔交易操作,一笔交易代表着一次买入与一次卖出,但是再次购买前必须卖出之前的股票
-
如果不能获取收益,请返回0
-
假设买入卖出均无手续费
数据范围:1≤𝑛≤105,股票的价格满足 1≤𝑣𝑎𝑙≤104
要求: 空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛)
进阶:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)
示例1
输入:[8,9,3,5,1,3]
返回值:4
说明:第三天(股票价格=3)买进,第四天(股票价格=5)卖出,收益为2 第五天(股票价格=1)买进,第六天(股票价格=3)卖出,收益为2 总收益为4。
示例2
输入:[9,8,4,1]
返回值:0
示例3
输入:[1,2,8,3,8]
返回值:12
说明:第一笔股票交易在第一天买进,第三天卖出;第二笔股票交易在第四天买进,第五天卖出;总收益为12。 因最多只可以同时持有一只股票,所以不能在第一天进行第一笔股票交易的买进操作,又在第二天进行第二笔股票交易的买进操作(此时第一笔股票交易还没卖出),最后两笔股票交易同时在第三天卖出,也即以上操作不满足题目要求。
备注:总天数不大于200000。保证股票每一天的价格在[1,100]范围内。
分析
dp[0][0]=0;不操作
dp[0][1]=-prices[0];第一次操作持有
dp[0][2]=0;第一次操作不持有
dp[0][3]=-prices[0];第二次操作持有
dp[0][4]=0;第二次操作不持有
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 两次交易所能获得的最大收益
* @param prices int整型一维数组 股票每一天的价格
* @return int整型
*/
public int maxProfit (int[] prices) {
// write code here
int [][] dp=new int[prices.length][5];
dp[0][0]=0;
dp[0][1]=-prices[0];
dp[0][2]=0;
dp[0][3]=-prices[0];
dp[0][4]=0;
for(int i=1;i<prices.length;i++){
dp[i][0]=dp[i-1][0];
dp[i][1]=Math.max(dp[i-1][1],-prices[i]);
dp[i][2]=Math.max(dp[i-1][2],dp[i-1][1]+prices[i]);
dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]-prices[i]);
dp[i][4]=Math.max(dp[i-1][4],dp[i-1][3]+prices[i]);
}
return dp[prices.length-1][4];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 两次交易所能获得的最大收益
# @param prices int整型一维数组 股票每一天的价格
# @return int整型
#
class Solution:
def maxProfit(self , prices: List[int]) -> int:
# write code here
dp=[[0] * 5 for _ in range(len(prices))]
dp[0][0]=0
dp[0][1]=-prices[0]
dp[0][2]=0
dp[0][3]=-prices[0]
dp[0][4]=0
for i in range(1,len(prices)):
dp[i][0]=dp[i-1][0]
dp[i][1]=max(dp[i-1][1],-prices[i])
dp[i][2]=max(dp[i-1][2],dp[i-1][1]+prices[i])
dp[i][3]=max(dp[i-1][3],dp[i-1][2]-prices[i])
dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[i])
return dp[len(prices)-1][4]