121. 買賣股票的最佳時機java
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。 若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。 注意你不能在買入股票前賣出股票。 示例 1: 輸入: [7,1,5,3,6,4] 輸出: 5 解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。 注意利潤不能是 7-1 = 6, 由於賣出價格須要大於買入價格。 示例 2: 輸入: [7,6,4,3,1] 輸出: 0 解釋: 在這種狀況下, 沒有交易完成, 因此最大利潤爲 0。
想要利潤最大,儘量地要保證購買的時候價格最低,總利潤最高。由此能夠列出狀態轉移方程。算法
buy = min{buy,price} profilt = max{profilt,price-buy}數組
public int maxProfit(int[] prices) { int profilt = 0; int buy = Integer.MAX_VALUE; for (int price : prices) { buy = Math.min(buy, price); profilt = Math.max(profilt, price - buy); } return profilt; }
數組的每一個索引作爲一個階梯,第 i個階梯對應着一個非負數的體力花費值 costi。spa
每當你爬上一個階梯你都要花費對應的體力花費值,而後你能夠選擇繼續爬一個階梯或者爬兩個階梯。.net
您須要找到達到樓層頂部的最低花費。在開始時,你能夠選擇從索引爲 0 或 1 的元素做爲初始階梯。設計
示例 1: 輸入: cost = [10, 15, 20] 輸出: 15 解釋: 最低花費是從cost[1]開始,而後走兩步便可到階梯頂,一共花費15。code
示例 2: 輸入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 輸出: 6 解釋: 最低花費方式是從cost[0]開始,逐個通過那些1,跳過cost[3],一共花費6。 注意: cost 的長度將會在 [2, 1000]。 每個 cost[i] 將會是一個Integer類型,範圍爲 [0, 999]。blog
以樣本爲例cost = [10, 15, 20] n = 3;索引
最後一步: 根據題意咱們知道,最後一步不必定是cost[2](即20),還有多是以後的值,咱們這裏假設有cost[3]且cost[3] = 0,這裏咱們就統一認爲最後一步是cost[3],由於它的須要用的體力值設置爲0。因此最後走到cost[2]所用的整體力值,和走到cost[3]的是同樣的。leetcode
子問題 最後一步消耗的體力值是cost[3],總共消耗的體力值爲f[3]。 走到了最後一步以後,往前回退,所面對的選擇是,要麼是倒退一步,要麼是倒退兩步。
因而有了子問題方程:
f[3] = min(f[1],f[2])+cost[3]
狀態轉移方程
f[x] = min(f[x-1],f[x-2])+cost[x]
初始條件 第一步能夠從cost[0]開始走,也能夠從cost[1]開始走。因而有了 f[0] = cost[0] f[1] = cost[1]
邊界 int costLength = cost.length; cost[costLengh+1] = 0 f[costLengh+1]爲最終的解。
public int minCostClimbingStairs(int[] cost) { int n = cost.length; int[] f = new int[n+1]; //初始化 f[0] = cost[0]; f[1] = cost[1]; for (int i = 2; i <= n; i++) { int tempCost = 0; if (i == n) { //cost[n] = 0 tempCost = 0; } else { tempCost = cost[i]; } f[i] = Math.min(f[i - 1], f[i - 2]) + tempCost; } return f[n]; }
假設你正在爬樓梯。須要 n 階你才能到達樓頂。
每次你能夠爬 1 或 2 個臺階。你有多少種不一樣的方法能夠爬到樓頂呢? 注意:給定 n 是一個正整數。
示例 1: 輸入: 2 輸出: 2 解釋: 有兩種方法能夠爬到樓頂。
- 1 階 + 1 階
- 2 階
示例 2: 輸入: 3 輸出: 3 解釋: 有三種方法能夠爬到樓頂。
- 1 階 + 1 階 + 1 階
- 1 階 + 2 階
- 2 階 + 1 階
最後一步:
最後一步是第n個臺階,咱們這邊假設爲4。
子問題 最後一步到第4個臺階,假設總共有走法f[4]。 若是是走到第3個臺階的話,就只能再走1步 若是走到第2個臺階的話,能夠走2步,或者走2次,分別走1步。
因而有了子問題方程:
f[4] = f[4-step1] + f[4-step2] f[4] = f[3] + f[2]
狀態轉移方程
f[x] = f[x-1] + f[x-2]
class Solution { public int climbStairs(int n) { int[] f = new int[n+1]; if(n<=2){ return n; } //初始化 f[0] = 0; f[1] = 1; f[2] = 2; //f[x] = f[x-1] + f[x-2] for(int i=3;i<=n;i++){ f[i] = f[i-1]+f[i-2]; } return f[n]; } }
給定一個整數數組 nums ,找到一個具備最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
示例: 輸入: [-2,1,-3,4,-1,2,1,-5,4], 輸出: 6 解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。 進階:
若是你已經實現複雜度爲 O(n) 的解法,嘗試使用更爲精妙的分治法求解。
分析能不能使用DP,要考慮符不符合DP的子問題重疊,即一個子問題,依賴於上一個子問題
簡化輸入,只有-2,則dp[0] 爲最大子序列和,dp[0] = -2,
假設只有,-2,1,則dp[1]會參考dp[0],會比較1與-2+1的大小,從而肯定要不要前面的-2,由此可得出
$dp[i] = \max\{ dp[i-1]+nums[i],nums[i]\} $
public static int maxSubArray(int[] nums) { // dp[i] = max(dp[i-1]+nums[i],nums[i]) int[] dp = new int[nums.length]; dp[0] = nums[0]; int res = dp[0]; for (int i = 1; i < nums.length; i++) { dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]); res = res > dp[i] ? res : dp[i]; } return res; }