Leetcode——70爬楼梯、120三角形的最小路径和

动态规划Dynamic Programming
1,递推(递归+记忆)
2.状态的定义:opt[n],dp[n],fib[n]
3,状态转移方程:opt[n]=best_of(opt[n-1],opt[n-2],…)
4.最优子结构

DP vs 回溯 vs 贪心
回溯(递归) ——重复计算
贪心——永远局部最优
DP——记录局部最优子结构/多种记录值

70.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。
示例1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

【实现代码】

package leetcode_50;

import java.util.Scanner;

public class Leetcode_70 {

	public static void main(String[] args){
		Scanner scanner=new Scanner(System.in);
		int n=scanner.nextInt();
		int result,result2;
		result=climbstairs(n);
		result2=climbstairs2(n);
		System.out.println(result2);
		System.out.print(result);
	}

	private static int climbstairs2(int n) {
		if(n<=2) return n;
		int one_step_before=2;
		int two_step_before=1;
		
		int all_ways=0;
		
		for(int j=2;j<n;j++){
			all_ways=one_step_before+two_step_before;
			two_step_before=one_step_before;
			one_step_before=all_ways;
		}
		return all_ways;
	}

	private static int climbstairs(int n) {
		if(n==0||n==1||n==2){
			return n;
		}
		int[] mem=new int[n];
		mem[0]=1;
		mem[1]=2;
		for(int i=2;i<n;i++){
			mem[i]=mem[i-1]+mem[i-2];
		}
		return mem[n-1];
		
	}
}

120.三角形的最小路径和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

自顶向下的最小路径和为11(即,2 + 3 + 5 + 1 = 11)。
【分析】
1.定义状态:dp[i,j]:是指从底走到i,j路径和的最小值。
2.方程;dp[i,j]=min(dp[i+1,j],dp[i+1,j+1])+本身这点的数据
3.初始状态:dp[m-1,j]=triangle[m-1.j]
【实现代码】

import java.util.ArrayList;
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int len=triangle.size();
		if(len==0) return 0;
		int[] dp=new int[triangle.size()];
		for(int i=0;i<triangle.size();i++){
			dp[i]=triangle.get(triangle.size()-1).get(i);
		}
		//从倒数第二层开始
		for(int i=triangle.size()-2;i>=0;i--){
			List<Integer> curlist=triangle.get(i);
			for(int j=0;j<curlist.size();j++)
				dp[j]=Math.min(curlist.get(j)+dp[j],curlist.get(j)+dp[j+1]);
		}
		return dp[0];
    }
}

152.乘积最大子序列
给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
示例1:

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

【思考】
1.状态:dp[i][2]
2.dp方程:
0:max
1:负max
(正的最大值)dp[i,0]= if a[i]>=0: dp[i-1,0]*a[i]
else :dp[i-1,1]*a[i]
(负的最大值)dp[i,1]= if a[i]>=0:dp[i-1,1]a[i]
else:dp[i-1,0]a[i]
以上的思想也就是利用动态规划,遍历数组计算当前最大值,不断更新。令imax为当前最大值,则当前最大值为Imax=max(imax
a[i],a[i])由于存在负数,导致最大的变最小,最小的变最大。因此还需要维护当前最小值imin,imin=min(imin
a[i],a[i])。当负数出现时,则imax与imin进行交换再进行下一步计算。
【实现代码】

package leetcode_50;

import java.util.Scanner;

import org.omg.PortableInterceptor.IORInterceptor;

public class leetcode_152 {

	public static void main(String[] args){
		int result;
		Scanner sc=new Scanner(System.in);
		String string=sc.nextLine();
		String[] s=string.split(" ");
		int[] a=new int[s.length];
		for(int i=0;i<s.length;i++){
			a[i]=Integer.parseInt(s[i]);
		}
		result=maxProduct(a);
		System.out.println(result);
	}

	private static int maxProduct(int[] a) {

		int max=Integer.MIN_VALUE,imax= 1,imin=1;
		for(int i=0;i<a.length;i++){
			if(a[i]<0){
				int tmp=imax;
				imax=imin;
				imin=tmp;
			}
			imax=Math.max(imax*a[i], a[i]);
			imin=Math.min(imin*a[i], a[i]);
			
			max=Math.max(max, imax);
		}
		return max;
	}

	
}

121.买卖股票最佳时机
【实现代码】


import numpy as np


def maxProfit(prices):
    if not prices: return 0;
    count=0
    res=0
    profit=[[0 for i in range(3)] for i in range(len(prices))]
    # profit=np.array(profit)
    print(profit)
    profit[0][0],profit[0][1],profit[0][2]=0,-prices[0],0

    for i in range(1,len(prices)):
        # print(i)
        profit[i][0]=profit[i-1][0]
        # print(profit[i][0])
        profit[i][1]=max(profit[i-1][1],profit[i-1][0]-prices[i])
        profit[i][2] = profit[i - 1][1] + prices[i]
        # print(profit[i][1])

        # print(profit[i][2])
        res=max(res,profit[i][0],profit[i][1],profit[i][2])

        # print(res)
        # if(res>0): count+=res
    print(res)




if __name__ == '__main__':
    line=input('请以空格为间隔连续输入一个数组')
    # a=line[1:len(line)-1]
    # a=a.split(" ")
    # a=[int(i) for i in a]
    a=[int(n) for n in line.split()]
    prices=a
    maxProfit(prices)
    # print(result)


300.最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。

【思路】
1.状态:dp[i]从头->i元素:最长子序列的长度
max(dp[0][1][2]…[n-1])
2.状态转移方程:
for i:0->n-1
dp[i]=Max{dp[j]}+1
注意:j:0->i-1且a[j]<a[i]
【实现代码】

// An highlighted block
package leetcode_50;

import java.util.Arrays;
import java.util.Scanner;

public class Leetcode_300 {

	public static void main(String[] args){
		int result;
		Scanner sc=new Scanner(System.in);
		String string=sc.nextLine();
		String[] s=string.split(" ");
		int[] a=new int[s.length];
		for(int i=0;i<s.length;i++){
			a[i]=Integer.parseInt(s[i]);
		}
		//result=maxProfit(a);
		result=lengthOfLIS(a);
		System.out.println(result);
	}

	private static int lengthOfLIS(int[] nums) {

		int[] dp=new int[nums.length+1];
		int res=1;
		Arrays.fill(dp, 1);
		int count=0;
		for(int i=0;i<nums.length;i++){
			for(int j=0;j<i;j++){
				if(nums[j]<nums[i]){
					//System.out.println(dp[i]);
					//System.out.println(i+" "+j);
					dp[i]=Math.max(dp[i], dp[j]+1);
					//dp[i]=dp[j]+1;
				}
			}
			//整体的最大值
			res=Math.max(res, dp[i]);
	
		}
//		for(int i=0;i<dp.length;i++){
//			System.out.println(dp[i]);
//		}
		return res;
	}
}

322.零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例1:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

示例2:

输入: coins = [2], amount = 3
输出: -1

说明:
你可以认为每种硬币的数量是无限的。
【思路】
可以理解为之前做过的**“爬楼梯”**问题,爬十一级台阶,一次爬一层,两层或五层。
动态规划:
1.状态:dp[i]:表示到第i级台阶的最少步数。
2.状态方程:
dp[i]=min{dp[i-coins[j]]}+1
【实现代码】

package leetcode_50;

import java.util.Arrays;
import java.util.Scanner;

public class Leetcode_322 {

	public static void main(String[] args){
		int result;
		Scanner sc=new Scanner(System.in);
		Scanner sc1=new Scanner(System.in);
		int amount=sc1.nextInt();
		String string=sc.nextLine();
		String[] s=string.split(",");
		int[] a=new int[s.length];
		for(int i=0;i<s.length;i++){
			a[i]=Integer.parseInt(s[i]);
		}
		result=coinChange(a,amount);
		System.out.println(result);
	}

	private static int coinChange(int[] coins, int amount) {
		
		//dp的大小
		int[] dp=new int[amount+1];
		Arrays.fill(dp, amount+1);
		dp[0]=0;
		//注意到amount
		for(int i=0;i<=amount;i++){
			for(int j=0;j<coins.length;j++){
				if(coins[j]<=i){
					dp[i]=Math.min(dp[i], dp[i-coins[j]]+1);
				}
			}
		}
		return dp[amount]>amount ? -1:dp[amount];
	}
}

72.编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符
示例1:

输入: word1 = "horse", word2 = "ros"
输出: 3
解释: 
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

示例2

输入: word1 = "intention", word2 = "execution"
输出: 5
解释: 
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

【思路】
1.状态:dp[i][j]:word1匹配到word2的前j个字符最少步数
i:单词1的前i个字符
j:单词2的前j个字符
结果为dp[m][n]
2.状态转移方程:
dp[i,j]= if w1[i]=w2[j] dp[i-1][j-1]
else: //插入,删除,替换
min(dp[i-1,j],dp[i,j-1],dp[i-1,j-1])+1(进行了一次操作要加一)
【实现代码】

package leetcode_50;

import java.util.Arrays;
import java.util.Scanner;

public class Leetcode_72 {

	public static void main(String[] args){
		int result;
		Scanner sc=new Scanner(System.in);
		Scanner sc1=new Scanner(System.in);
		String word1=sc.nextLine();
		String word2=sc.nextLine();
		result=minDistance(word1,word2);
		System.out.println(result);
	}

	private static int minDistance(String word1, String word2) {

		int m=word1.length();
		int n=word2.length();
		int[][] dp=new int[m+1][n+1];
//		for(int i=0;i<m+1;i++)
//			for(int j=0;j<n+1;j++){
//				dp[i][j]=0;
//			}

		for(int i=0;i<m+1;i++){
			dp[i][0]=i;
		}
		for(int j=0;j<n+1;j++){
			dp[0][j]=j;
		}
		
		for(int i=1;i<m+1;i++)
			for(int j=1;j<n+1;j++){
				if(word1.charAt(i-1)==word2.charAt(j-1)){
					dp[i][j]=min(dp[i-1][j-1], dp[i-1][j]+1,dp[i][j-1]+1);
				}else{
					dp[i][j]=min(dp[i-1][j-1]+1, dp[i-1][j]+1,dp[i][j-1]+1);
				}
			}
		return dp[m][n];
	}

	private static int min(int i, int j, int k) {
		int min=Math.min(i, j);
		min=(min<k)?min:k;
		return min;
	}
	
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章