买卖股票的最佳时机

假设有一个数组,它的第i个元素是一支给定的股票在第i天的价格。如果你最多只允许完成一次交易(例如,一次买卖股票),设计一个算法来找出最大利润。

样例

给出一个数组样例 [3,2,3,1,2], 返回 1

解题

法一:直接暴力,时间发杂度O(N2)

public class Solution {
/**
* @param prices: Given an integer array
* @return: Maximum profit
*/
public int maxProfit(int[] prices) {
// write your code here
int Max = 0;
if( prices == null || prices.length == 0)
return 0; for(int i = 0;i< prices.length ;i++){
for(int j = i;j< prices.length ;j++)
Max = Math.max(Max, prices[j] - prices[i]);
}
return Max;
}
}

法二:动态规划,选取最小的卖,最大的买,利润最大。

public class Solution {
/**
* @param prices: Given an integer array
* @return: Maximum profit
*/
public int maxProfit(int[] prices) {
// write your code here
int result = 0;
if( prices == null || prices.length == 0)
return 0;
int minbuy = prices[0];
for(int i = 1;i< prices.length ;i++){
// 最小的购买,最大的卖
result = Math.max(result,prices[i] - minbuy);
minbuy = Math.min(minbuy,prices[i]);
}
return result;
}
}

时间复杂度O(N)

Python

class Solution:
"""
@param prices: Given an integer array
@return: Maximum profit
"""
def maxProfit(self, prices):
# write your code here
if prices == None or len(prices) ==0:
return 0
Min = prices[0]
res = 0
for p in prices:
res = max(res,p-Min)
Min = min(Min,p)
return res

法三:分治法

参考《算法导论》

题目要求的是一次购买,一次卖出使得所获价格变化最大。可以考虑每一天的价格变化,第i天的价格变化 等于第i天的价格减去i-1天的价格,这样就会有许多价格变化的数据形成的数组,求这个数组的连续子数组的和的最大值就是答案了。为什么这个这个最大连续子数组就是答案?

假设原始数组是:,若最大收益是 an - a1

相邻差数组是:,显然这个的连续和也是an - a1

问题转化为求最大连续子数组

对上图的例子:

分治法求解最大子数组

假定我们要寻找子数组A[low,...,high]的最大子数组。使用分治法意味着我们要将子数组分成两个规模尽量相同的子数组。也就是说,找到子数组的中央位置,比如:mid,然后考虑求两个子数组A[low,...,mid] 和A[mid+1,...,high]。

A[low,...,high]的然后连续子数组A[i,...,j]所处的位置必然是一下三种情况之一:

(1)完全位于子数组A[low,...,mid]中,因此low<=i<=j<=mid

(2)完全位于子数组A[mid+1,...,high]中,因此mid+1<=i<=j<=high

(3)跨越了中间点,因此low<=i<=mid<=j<=high

所以,可以递归的求解(1)(2)两种情况的最大子数组,剩下的就是对(3)情况寻找跨越中间点的最大子数组,然后在三种情况中选取和最大者。如下图所示

对于跨越中间点的最大子数组,可以在线性时间内求解。可以找出A[i,...,mid] 和A[mid+1,...,j]的最大子数组,合并就是答案。

参考算法导论写的寻找经过中间点时候的最大连续子数组

    public int findMaxCrossingSubarray(int[] A,int low,int mid,int high){
if(low > mid || mid>high)
return Integer.MIN_VALUE;
int leftSum = Integer.MIN_VALUE;
int rightSum = Integer.MIN_VALUE;
int sum = 0;
int maxleft = -1;
int maxright = -1;
for(int i = mid;i>=low;i--){
sum+=A[i];
if( sum >= leftSum){// 向左只要和增加就更新
leftSum = sum;
maxleft = i;
}
}
sum = 0;
for(int j = mid+1;j<=high;j++){
sum+=A[j];
if(sum>=rightSum){
rightSum = sum;
maxright = j;
}
}
return leftSum + rightSum;
}

算法导论上的伪代码

时间复杂度O(N)

上面有返回的边界,我只是返回了子数组的最大值

下面在递归的求解整个数组的最大连续子数组

    public int findMaxSubarray(int[] A,int low,int high){
if(low == high)
return Math.max(A[low],0);
else{
int mid = low + (high - low)/2;// 防止越界
int leftSum = findMaxSubarray(A,low,mid);//(1)
int rightSum = findMaxSubarray(A,mid+1,high);//(2)
int midSum = findMaxCrossingSubarray(A,low,mid,high);//(3)
int sum = Math.max(leftSum,rightSum);
sum = Math.max(sum,midSum);
sum = Math.max(sum,0);
return sum;
}
}

上面标的(1)( 2)( 3)对应上面分析的(1)(2)(3)

上面代码中最后的结果和0求了最大值,lintcode测试用例可以不买不卖的情况,由于买了一定会亏,就不买了的情况,题目要求最大一次交易,就是可以不交易的了。

算法导论上的伪代码

时间复杂度分析:

递归情况:

 这个等式很显然的

当n=1的时候就是O(1)

所以:

时间复杂度是:

具体时间复杂度求解参考《算法导论》

对于求解最大子数组,当然也可以运用动态规划求解

全部程序

public class Solution {
/**
* @param prices: Given an integer array
* @return: Maximum profit
*/
public int maxProfit(int[] prices) {
// write your code here
if(prices == null || prices.length == 0)
return 0;
int[] A = new int[prices.length - 1];
for(int i = 1;i<prices.length ;i++)
A[i-1] = prices[i] - prices[i-1];
int maxSubarray = findMaxSubarray(A,0,A.length - 1);
return maxSubarray;
}
public int findMaxSubarray(int[] A,int low,int high){
if(low == high)
return Math.max(A[low],0);
else{
int mid = low + (high - low)/2;// 防止越界
int leftSum = findMaxSubarray(A,low,mid);//(1)
int rightSum = findMaxSubarray(A,mid+1,high);//(2)
int midSum = findMaxCrossingSubarray(A,low,mid,high);//(3)
int sum = Math.max(leftSum,rightSum);
sum = Math.max(sum,midSum);
sum = Math.max(sum,0);
return sum;
}
}
public int findMaxCrossingSubarray(int[] A,int low,int mid,int high){
if(low > mid || mid>high)
return Integer.MIN_VALUE;
int leftSum = Integer.MIN_VALUE;
int rightSum = Integer.MIN_VALUE;
int sum = 0;
int maxleft = -1;
int maxright = -1;
for(int i = mid;i>=low;i--){
sum+=A[i];
if( sum >= leftSum){// 向左只要和增加就更新
leftSum = sum;
maxleft = i;
}
}
sum = 0;
for(int j = mid+1;j<=high;j++){
sum+=A[j];
if(sum>=rightSum){
rightSum = sum;
maxright = j;
}
}
return leftSum + rightSum;
}
}

lintcode:买卖股票的最佳时机 I的更多相关文章

  1. lintcode:买卖股票的最佳时机 IV

    买卖股票的最佳时机 IV 假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格. 设计一个算法来找到最大的利润.你最多可以完成 k 笔交易. 注意事项 你不可以同时参与多笔交易(你必须在再次 ...

  2. lintcode:买卖股票的最佳时机 III

    买卖股票的最佳时机 III 假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格.设计一个算法来找到最大的利润.你最多可以完成两笔交易. 样例 给出一个样例数组 [4,4,6,1,1,4,2 ...

  3. lintcode:买卖股票的最佳时机 II

    买卖股票的最佳时机 II 假设有一个数组,它的第i个元素是一个给定的股票在第i天的价格.设计一个算法来找到最大的利润.你可以完成尽可能多的交易(多次买卖股票).然而,你不能同时参与多个交易(你必须在再 ...

  4. python买卖股票的最佳时机--贪心/蛮力算法简介

    开始刷leetcode算法题 今天做的是“买卖股票的最佳时机” 题目要求 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更 ...

  5. 2、买卖股票的最佳时机 II

    2.买卖股票的最佳时机 II 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能 ...

  6. Leetcode——121. 买卖股票的最佳时机

    题目描述:买卖股票的最佳时机 题目要求求解能获得最大利润的方式? 可以定一个二维数组 d [ len ] [ 2 ] ,其中d[ i ][ 0 ] 表示前i天可以获得的最大利润:d[ i ][ 1 ] ...

  7. Leecode刷题之旅-C语言/python-121买卖股票的最佳时机

    /* * @lc app=leetcode.cn id=121 lang=c * * [121] 买卖股票的最佳时机 * * https://leetcode-cn.com/problems/best ...

  8. leecode刷题(2)-- 买卖股票的最佳时机

    买卖股票的最佳时机 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能同时参与多 ...

  9. Leetcode 188.买卖股票的最佳时机IV

    买卖股票的最佳时机IV 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你最多可以完成 k 笔交易. 注意: 你不能同时参与多笔交易(你必 ...

随机推荐

  1. 10个 iOS 用户暂可以嘲笑 Android 的特点

    Android 与 iOS 设备之间的争斗从未停止,毕竟一切高科技产品的理念和实际表现方式都不相同.就拿 Android 来说,很多功能令用户并 不太开心,甚至是令人愤怒,下面让我们来简单的盘点 10 ...

  2. C#判断字符串为空

    string str = null; if (string.IsNullOrWhiteSpace(str)) { MessageBox.Show("字符串为null"); } if ...

  3. JAVA栈实例—括号匹配

    import java.util.Stack; public class test { public static void main(String[] args){ System.out.print ...

  4. c++中的struct

    c++中的struct不在是c中的struct,不仅仅是一个多个数据类型的结构体了.c++中的struct可以具有成员函数(c语言中是不可以的),c++ struct还可以继承class等等.同时c+ ...

  5. css3 forwards、backwards、both

    animation-fill-mode 属性规定动画在播放之前或之后,其动画效果是否可见. none 不改变默认行为. forwards 当动画完成后,保持最后一个属性值(在最后一个关键帧中定义). ...

  6. Visual Studio 2013 各版本注册码

    Visual Studio Ultimate 2013 KEY(密钥):BWG7X-J98B3-W34RT-33B3R-JVYW9 Visual Studio Premium 2013 KEY(密钥) ...

  7. ZeroMQ 在 centos 6.5_x86_64 下的安装

    ZeroMQ 在 centos 6.5_x86_64 下的安装 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.ZeroMQ介绍 ZeroMQ是一个开 ...

  8. JS 学习笔记--2--变量的声明

      1.ECMAScript 中规定所有的关键字.保留字.函数名.函数名.操作符等都是区分大小写的. 2.标识符:指变量.函数.属性的名字:标识符组成:以字母.下划线.$ 开头,其他字母可以含有数字, ...

  9. 【BZOJ】【3207】花神的嘲讽计划 I

    字符串Hash+可持久化线段树 好神奇的转化…… 蒟蒻一开始还去想AC自动机去了……然而由于a[i]的范围是小于等于n,怎么也想不出一个时间复杂度合理的方法 膜拜了题解0.0原来是字符串Hash! 首 ...

  10. 使用Provider时提示:Unable to get provider...

    具体原因还不清楚,只是找到了原因: 这是因为自定义的Provider放的包路径不对,自定义的Provider应该放到和MainActivity同一个包中.