leetcode(121)(122)(123)(188) Best Time to Buy and Sell Stock I/II/III/IV JAVA代码

来源:互联网 发布:matlab编程第刘卫国 编辑:程序博客网 时间:2024/06/05 02:53

原题链接:

https://leetcode.com/problems/best-time-to-buy-and-sell-stock

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-II

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-III

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-IV

第一题

这道题比较简单,只允许交易一次,得到最大收益。只要找到两天价格差最大即可

按照此思路,代码如下:

package leetcode;public class BestTimetoBuyAndSellStock {// https://leetcode.com/problems/best-time-to-buy-and-sell-stock/public static int maxProfit(int[] prices) {int len = prices.length;if (prices == null || len <= 1) {return 0;}int minPrice = prices[0]; // 最小价格初始化int diff = prices[1] - prices[0];// 价格差for (int i = 2; i < len; i++) {minPrice = Math.min(prices[i-1], minPrice);if(diff<prices[i]-minPrice){diff=prices[i]-minPrice;}}if(diff<0){return 0;}return diff;}public static void main(String[] args) {// TODO Auto-generated method stubint[] prices = { 1, 3, 5, 6, 1, 2, 9 };System.out.println(maxProfit(prices) + "");}}


上面先找到最小价格,然后用最小价格与当前搜索到的位置进行减法操作,最后得到最大的价格差。

还有一种解法,维护两个变量,一个代表当前最大收益local,一个代表全局最大收益global,local是上一次当前收益加上后面两天收益的价差得到,全局收益是指全局收益与此次当前收益取最大值。这样,local的值实质上是此时卖出价格与第一次买入时的价差,global可以记录价差的最大值。大家可以运行代码单步调试来理解这个方法,代码如下:

package leetcode;public class BestTimetoBuyAndSellStock {// https://leetcode.com/problems/best-time-to-buy-and-sell-stock/public static int maxProfit(int[] prices) {if (prices == null || prices.length <= 1) {return 0;}int local = 0;int global = 0;for (int i = 0; i < prices.length - 1; i++) {local = Math.max(local + prices[i + 1] - prices[i], 0);// 当前最大收益global = Math.max(local, global);// 全局最大收益}return global;}public static void main(String[] args) {// TODO Auto-generated method stubint[] prices = { 1, 3, 5, 6, 1, 2, 9 };System.out.println(maxProfit(prices) + "");}}


第二题:

这里同第一次差别为可以购买无数次,这道题可以这样想,根据第一题第二种解法,可以知道当前最大收益本地值,当时只允许买卖一次,所以用一个global来记录最大收益。现在可以允许买卖无数次,所以不需要global去记录最大收益,只要收益为正的时候,就可以进行买入卖出。,所以只要前后两次价差为正即可加到收益中去。代码如下:

package leetcode;import java.lang.reflect.Array;public class BestTimeToBuyAndSellStockII {// https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/public static int maxProfit(int[] prices) {if (prices == null || prices.length == 0) {return 0;}int len = prices.length;int maxProfit = 0;for (int i = 1; i < len; i++) {int tempProfit = prices[i] - prices[i - 1];if (tempProfit > 0) {maxProfit += tempProfit;}}return maxProfit;}public static void main(String[] args) {// TODO Auto-generated method stubint[] prices = { 1 };System.out.println(maxProfit(prices) + "");}}


第三题:

可以买入两次。这时可以用动态规划的算法来做了,但是我到第四题的时候可以买入k次条件时再用动态规划,这里用另外一种方法。

这里我们创建两个数组ArrayA与ArrayB,一个记录从前向后遍历得到的最大价差,一个记录从后向前遍历得到的最大价差。最后两个相加后得到的最大值即为最大收益。代码如下:

package leetcode;public class BestTimetoBuyAndSellStockIII {// https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/public static int maxProfit(int[] prices) {if (prices == null || prices.length == 0) {return 0;}int len = prices.length;int sum = 0;int min = prices[0];int[] ArrayA = new int[len];for (int i = 1; i < prices.length; i++) {ArrayA[i] = prices[i] - min;ArrayA[i] = ArrayA[i] > ArrayA[i - 1] ? ArrayA[i] : ArrayA[i - 1];if (prices[i] < min) {min = prices[i];}}int max = prices[prices.length - 1];int[] ArrayB = new int[len];for (int i = len - 1; i > 0; i--) {ArrayB[i] = max - prices[i];ArrayB[i] = ArrayB[i] > ArrayB[i - 1] ? ArrayB[i] : ArrayB[i - 1];if (prices[i] > max) {max = prices[i];}}for (int i = 0; i < len; i++) {sum = Math.max(ArrayA[i] + ArrayB[i], sum);}return sum;}public static void main(String[] args) {// TODO Auto-generated method stubint[] prices = { 1, 3, 5, 6, 1, 2, 9 };System.out.println(maxProfit(prices) + "");}}
这个思路很容易理解,前后两次价差相加。


第四题:

买入k次,这次就只能用动态规划的思想了。之前不了解动态规划的同学,可以先看背包问题九讲!!!,讲的很好,之后我也回把背包问题的代码贴出来。

背包问题九讲链接地址:http://love-oriented.com/pack/(必看)

首先先按照第二题思路,求得最大收益值与最大交易次数(无限次条件)。如果交易次数k大于最大交易次数,则最终结果就是最大收益。

如果k小于最大交易次数,则使用动态规划的方法求解收益最大值。

第四题代码:

package leetcode;public class BestTimetoBuyAndSellStockIV {// https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/public static int maxProwt(int k, int[] prices) {int days = prices.length;int tradeCount = 0;// 交易次数int profitCount = 0;// 收益int rangeProfitCount = 0;for (int i = 1; i < days; i++) {if (prices[i - 1] < prices[i]) {// 两天之间收益为正值rangeProfitCount += prices[i] - prices[i - 1];if (i == days - 1) {// 最后一天profitCount += rangeProfitCount;tradeCount += 1; // 交易次数加一}} else if (rangeProfitCount > 0) {profitCount += rangeProfitCount; // 收益加上tradeCount += 1; // 交易次数加一rangeProfitCount = 0;}}if (k >= tradeCount) {// 如果k交易次数大于等译交易总次数,直接返回最大收益return profitCount;}int[][] global = new int[k + 1][days];int[][] local = new int[k + 1][days];// 动态规划for (int i = 1; i <= k; i++) {for (int j = 1; j < days; j++) {int diff = prices[j] - prices[j - 1];local[i][j] = Math.max(global[i - 1][j - 1], local[i][j - 1] + diff);global[i][j] = Math.max(global[i][j - 1], local[i][j]);}}return global[global.length - 1][global[0].length - 1];}public static void main(String[] args) {// TODO Auto-generated method stubint[] prices = { 1, 3, 5, 6, 1, 2, 9 };System.out.println(maxProwt(3, prices) + "");}}

附:背包问题代码(包含01背包,完全背包,多重背包求解方法)

package pack;import java.util.ArrayList;import java.util.List;import org.omg.CORBA.SystemException;public class Pack {private static int N = 4; // 物品个数private static int V = 10; // 背包最大容量private int[] f;// 前i件物品放入容量为j的背包得到的最大价值f[j]private static int G=2;//分组背包问题组数// 状态转移方程f[v]=max{f[v],f[v-cost]+weight};public Pack() {super();resetF();}private void resetF() {f = new int[V + 1];for (int i = 0; i < f.length; i++) {f[i] = 0;}}/** * 01背包 *  * @param cost *            消耗容量 * @param weight *            体积 * @return */private void ZeroOnePack(int cost, int weight) {for (int v = V; v >= cost; v--) {f[v] = Math.max(f[v], f[v - cost] + weight);}}/** * 完全背包 *  * @param cost *            消耗容量 * @param weight *            体积 * @return */private void CompletePack(int cost, int weight) {for (int v = cost; v <= V; v++) {f[v] = Math.max(f[v], f[v - cost] + weight);}}/** * 多重背包 *  * @param cost * @param weight * @param amount */private void MultiplePack(int cost, int weight, int amount) {if (cost * amount >= V) {CompletePack(cost, weight);return;}int k = 1;while (k < amount) {ZeroOnePack(k * cost, k * weight);amount = amount - k;k = k * 2;}ZeroOnePack(amount * cost, amount * weight);}public static void main(String[] args) {// TODO Auto-generated method stubint[] cost = { 6, 3, 4, 2 };int[] weight = { 30, 14, 16, 9 };int[] amount = { 0, 1, 2, 3 };Pack zo = new Pack();/************01背包************/zo.resetF();for (int i = 0; i < N; i++) {zo.ZeroOnePack(cost[i], weight[i]);}System.out.println(zo.f[V] + "");/************完全背包 ************/zo.resetF();for (int i = 0; i < N; i++) {zo.CompletePack(cost[i], weight[i]);}System.out.println(zo.f[V] + "");/************多重背包************/zo.resetF();for (int i = 0; i < N; i++) {zo.MultiplePack(cost[i], weight[i], amount[i]);}System.out.println(zo.f[V] + "");}}

同时还有一篇讲动态规划的文章推荐给大家:http://www.cnblogs.com/sdjl/articles/1274312.html

同时附录出文章中的C++代码:

#include<iostream>#include<fstream>using namespace std;//http://www.cnblogs.com/sdjl/articles/1274312.htmlconst int max_n=100;//程序支持的最多金矿数const int max_people=10000;//程序支持的最多人数int n;//金矿数int peopleTotal;//可以用于挖金子的人数int peopleNeed[max_n];//每座金矿需要的人数int gold[max_n];//每座金矿能够挖出来的金子数int maxGold[max_people][max_n];//maxGold[i][j]保存了i个人挖前j个金矿能够得到的最大金子数,等于-1表示未知//初始化数据void init(){    ifstream inputFile("beibao.in");    inputFile>>peopleTotal>>n;    for(int i=0;i<n;i++){        inputFile>>peopleNeed[i]>>gold[i];    }    inputFile.close();    for(int i=0;i<=peopleTotal;i++){        for(int j=0;j<n;j++){            maxGold[i][j]=-1;//等于-1时表示未知        }    }}//获得在仅有people个人和前mineNum个金矿时能够得到的最大金子数int GetMaxGold(int people,int mineNum){    int retMaxGold; //返回的最大金子数    if(maxGold[people][mineNum]!=-1){//如果曾经这个问题已经计算过        retMaxGold=maxGold[people][mineNum];//获得保存起来的值    }    else if(mineNum==0){//如果仅有一个金矿        if(people>peopleNeed[mineNum]){            retMaxGold=gold[mineNum];        }else{//否则一个矿也不能开采            retMaxGold=0;        }    }    else if(people>=peopleNeed[mineNum]){//人数够开采此矿        retMaxGold=max(GetMaxGold(people-peopleNeed[mineNum],mineNum-1)+gold[mineNum],GetMaxGold(people,mineNum-1));//两种情况,要么开采此矿剩下的人采其它矿;要么不开采此矿,所有人开采下一个矿.两者取最大值    }    else{//剩下的人无法开采此矿,直接开采下一个矿        retMaxGold=GetMaxGold(people,mineNum-1);    }    maxGold[people][mineNum]=retMaxGold;//记录下当前人数能采mineNum号矿的最大值    return retMaxGold;}int main(){    init();    cout<<GetMaxGold(peopleTotal,n-1);    //return 0;}

0 0
原创粉丝点击