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;
	}
	
}

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