121. 买卖股票的最佳时机& 1911. 最大子序列交替和

发布时间 2023-07-11 11:22:10作者: noobwei

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock

int maxProfit(int* prices, int pricesSize){
    int minp=INT_MAX;	//最小价格
    int max=0;			//最大差值
    for(int i=0;i<pricesSize;i++){
        if(prices[i]<minp)   minp=prices[i];
        else if(prices[i]-minp>max) max=prices[i]-minp;
    }
    return max;
}

可以使用fmax和fmin代替

int maxProfit(int* prices, int pricesSize){
    int minp=INT_MAX;
    int max=0;
    for(int i=0;i<pricesSize;i++){
        minp=fmin(prices[i],minp);
        max=fmax(prices[i]-minp,max);
    }
    return max;
}

然而后者的运算时间更长

“fmin”和“fmax”函数分别用于查找最小值和最大值。与直接比较运算符相比,这些函数涉及额外的操作和函数调用。此外,这些函数还可能涉及浮点运算。

相比之下,第一个函数使用“<”和“>”直接比较,这是简单的整数比较操作。与“fmin”和“fmax”函数相比,这些操作通常更快,需要更少的计算开销。

回到每日一题 1911. 最大子序列交替和
一个下标从 0 开始的数组的 交替和 定义为 偶数 下标处元素之 和 减去 奇数 下标处元素之 和 。

比方说,数组 [4,2,5,3] 的交替和为 (4 + 5) - (2 + 3) = 4 。
给你一个数组 nums ,请你返回 nums 中任意子序列的 最大交替和 (子序列的下标 重新 从 0 开始编号)。

一个数组的 子序列 是从原数组中删除一些元素后(也可能一个也不删除)剩余元素不改变顺序组成的数组。比方说,[2,7,4] 是 [4,2,3,7,2,1,4] 的一个子序列(加粗元素),但是 [2,4,2] 不是。
示例 1:

输入:nums = [4,2,5,3]
输出:7
解释:最优子序列为 [4,2,5] ,交替和为 (4 + 5) - 2 = 7 。
示例 2:

输入:nums = [5,6,7,8]
输出:8
解释:最优子序列为 [8] ,交替和为 8 。
示例 3:

输入:nums = [6,2,1,2,4,5]
输出:10
解释:最优子序列为 [6,1,5] ,交替和为 (6 + 5) - 1 = 10 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-alternating-subsequence-sum

long long maxAlternatingSum(int* nums, int numsSize){
    long long left = nums[0], right = 0;
    for(int i = 1; i < numsSize; i++){
        long long tmp = left;
        left = fmax(left, right + nums[i]); //当nums[i]作为偶数下标
        right = fmax(right, tmp - nums[i]); //当nums[j]作为奇数下标
    }
    return left;
}

该函数使用动态编程方法有效计算最大交替和。它从第二个元素(索引1)开始遍历数组nums。对于索引i的每个元素,它计算两个值: 左 "和 "右"。

  • left "表示如果 "nums[i]"作为子序列中偶数索引处的元素被包含时的最大交替和。
  • right 表示如果 nums[i] 是子序列中奇数索引的元素,最大交替和。

为了计算这些值,函数使用了fmax函数来比较和更新每次迭代的最大交替和。使用的公式如下

tmp = left;
left = fmax(left, right + nums[i])
right = fmax(right, tmp - nums[i])
由于先存了left的值在tmp里面,所以这里的right中的tmp是没有加新数字的left
因为把上面的nums[i]移到左边,与下面的fmax判断一致,所以可以判断两种不同的情况

这里,tmp存储了left的前一个值,以避免过早覆盖。

在遍历整个数组后,函数返回left的最终值,它代表给定数组nums的最大交替和。
比如:

  • 在索引1,left = fmax(4, 0 + 2) = 4right = fmax(0, 4 - 2) = 2
  • 索引2,左 = fmax(4, 2 + 5) = 7右 = fmax(2, 4 - 5) = 2
  • 索引3,左 = fmax(7, 2 + 3) = 7右 = fmax(2, 7 - 3) = 4
    在fmax中选定了left则表示把继承前面一个right的值,前面一个数为奇数位的时候可以达到更大值

即使在前面一次比较中比较小,也会保留至下一轮比较中
且保留left的前提是前面已经计算过一次right,right的前提已经计算过一次left,所以可以正常模拟流程