【算法】使用双指针解决字节一面股票交易问题

【算法】使用双指针解决字节一面股票交易问题

  • 题前唠嗑:hello,早上坐高铁,无聊看看订阅号,看到这样一篇文章,一位面试字节的小伙伴遇到了股票交易这么一道题,我当时就联想到了LeetCode求水池最多容纳的水量问题,结合两题和大家伙分享一波拙见_
  • 题目描述:给定一个数组prices,它的第i个元素 prices[i]表示一支给定股票第i天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0。
  • 举例:pirces[]={10,8,6,2,5,4,8,3,7}

    备注:不考虑实际股票交易中的细节问题

  • 股票交易问题
    • 图示

    • 思路

      1. 设置两个指针left和right,left代表买入时机,right代表卖出时机,买入时机必早于卖出时机即left<right;买入价格为prices[left],卖出价格为prices[right];收益(E)为(卖出价格-买入价格)*(卖出时机-买入时机)即E=(prices[right]-prices[left])*(right-left);
      2. 初始位置left=0,right=prices.length-1;
      3. 确定移动哪个指针(更改买入或卖出时机获得更大的价差),即比较 prices[right-1]-prices[left] 和 prices[right]-prices[left+1]的大小;case:prices[right-1]-prices[left] > prices[right]-prices[left+1], 对应卖出时机提前一天获得更大价格差的场景,则:right–;case:prices[right-1]-prices[left] <= prices[right]-prices[left+1],对应买入时机后延一天获得更大价格差的场景,则:left++;
      4. 比较移动前移动后两者收益,取较大者,直至买入时机无法早于卖出时机即left不大于right,此时收益为最大收益。
    • 注意事项:不要对prices[right]-prices[left]做取绝对值处理,这种情况对应的是收益为负。

    • 代码

    public int maxEarn(int [] prices){
        if(prices==null||prices.length==0){
            return 0;
        }
        int left=0;
        int right=prices.length-1;
        int maxearn=(prices[right]-prices[left])*(right-left);
        while (left<right){//控制买入时机必早于卖出时机
            if((prices[right-1]-prices[left])>(prices[right]-prices[left+1])){
                right--;
            }else {
                left++;
            }
            maxearn=Math.max(maxearn,(prices[right]-prices[left])*(right-left));
        }
        //收益为负或0则都设为0
        if(maxearn<=0){
            maxearn=0;
        }
        return maxearn;
    }
    
  • 求水池最多容纳的水量问题

    官方题目描述:给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

    为了与上述prices区分,这里使用height作为传入参数的名字,值不变,即height={10,8,6,2,5,4,8,3,7}

    • 图示

    • 思路

      1. 设置两个指针left和right,left代表水池左边墙的位置,right代表水池右边墙的位置;左右墙高度分别为height[left],height[right];所能容纳的水量V=左右墙较矮的墙高*两墙间距,即V=min(height[left],heigth[right])*(right-left);
      2. 初始位置left=0,right=prices.length-1;
      3. 确定移动哪个指针,此处逻辑比较简单,移动两墙中矮的那个墙才有可能获得更大的水池容量,case:height[left]>height[right],左墙高于右墙,移动右墙,则:right–;case:height[left]<=height[right],左墙矮(或等)于右墙,移动左墙,则:left++;
      4. 比较移动前移动后两者容量,取较大者,直至左墙无法在右墙的左边,即left不大于right,此时容量为最大容量。
    • 代码

public int maxArea(int[] height) {
    if(height==null||height.length==0){
        return 0;
    }
    int left=0;
    int right=height.length-1;
    int maxarea=Math.min(height[left],height[right])*(right-left);
    while (left<right) {//左边的墙必在右边的墙左边
        if(height[left]<=height[right]){
            left++;
        }else {
            right--;
        }
        maxarea=Math.max(maxarea,Math.min(height[left],height[right])*(right-left));
    }
    return maxarea;
}

  • 总结
    1. 在解决类似的问题时,应该把具体的问题抽象出来,买入时机、左墙抽象为左指针,卖出时机、右墙抽象为右指针;
    2. 先用文字描述出求取结果的表达式如:收益(E)为(卖出价格-买入价格)*(卖出时机-买入时机)、所能容纳的水量V=左右墙较矮的墙高*两墙间距,再将文字描述转化为数学描述;
    3. 使用双指针的关键点在于指针移动的终止条件确定移动哪个指针

鄙人拙见,如有不当之处,望各位不吝赐教,互相交流,共同成长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值