当前位置: 首页 > news >正文

lintcode:买卖股票的最佳时机 I

买卖股票的最佳时机

假设有一个数组,它的第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;
    }
}

 

相关文章:

  • PHP处理一个5G文件,使用内存512M的,数据为整形,从大到小排序,优化排序算法...
  • c++的this指针
  • CM android的CMUpdater分析(二)
  • Saving HDU hdu
  • activiti 动态配置 activiti 监听引擎启动和初始化(高级源码篇)
  • Webview组件和HTML的介绍
  • [一句秒懂]高仿QQ底部小红点弹簧效果
  • 安全关闭多Activity的Application
  • Android自定义控件之日历控件
  • path去除多余“/”和添加“/”正则
  • JS魔法堂:doctype我们应该了解的基础知识
  • CSS3魔法堂:禁止用户改变textarea大小
  • 音效
  • 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法...
  • ssl证书的对称密钥与非对称密钥
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • AWS实战 - 利用IAM对S3做访问控制
  • C# 免费离线人脸识别 2.0 Demo
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • echarts的各种常用效果展示
  • ES学习笔记(12)--Symbol
  • express + mock 让前后台并行开发
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JavaScript新鲜事·第5期
  • java多线程
  • Laravel核心解读--Facades
  • Node项目之评分系统(二)- 数据库设计
  • Vue 重置组件到初始状态
  • 飞驰在Mesos的涡轮引擎上
  • 关于springcloud Gateway中的限流
  • 如何设计一个微型分布式架构?
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 小而合理的前端理论:rscss和rsjs
  • 小李飞刀:SQL题目刷起来!
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用element的upload组件实现多图片上传和压缩
  • 在Mac OS X上安装 Ruby运行环境
  • 阿里云重庆大学大数据训练营落地分享
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • #pragma data_seg 共享数据区(转)
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)计算机毕业设计ssm电影分享网站
  • (全注解开发)学习Spring-MVC的第三天
  • (一)插入排序
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • *2 echo、printf、mkdir命令的应用
  • ../depcomp: line 571: exec: g++: not found
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .net CHARTING图表控件下载地址
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件