股票价格调整问题

问题描述

小M的任务是调整一只股票的价格,使其符合一个给定的正整数序列p0,p1,…,pn−1p0​,p1​,…,pn−1​,并且要确保每个月的股票上涨系数不能超过某个百分比kk。上涨系数定义为当月价格相对于之前所有月份价格总和的比例。如果上涨系数超过k%k%,就需要对某些月份的价格进行调整,以尽量减少对整体序列的变更。

你需要输出在保证上涨系数不超过k%k%的情况下,最少需要增加的价格总和。


测试样例

样例1:

输入:n = 5,k = 12,p = [1000, 34, 12, 27, 131]
输出:19

样例2:

输入:n = 4,k = 10,p = [100, 1, 1, 1]
输出:0

样例3:

输入:n = 6,k = 15,p = [500, 50, 30, 20, 10, 60]
输出:0

问题理解

你需要调整股票价格序列,使得每个月的上涨系数不超过给定的百分比 k。上涨系数定义为当月价格相对于之前所有月份价格总和的比例。如果某个上涨系数超过了 k%,你需要增加某些月份的价格,以尽量减少对整体序列的变更。

数据结构选择

  • 我们可以使用一个数组来存储每个月的价格。
  • 使用一个变量来记录之前所有月份价格的总和。

算法步骤

  1. 初始化

    • 初始化一个变量 total_sum 来记录之前所有月份价格的总和。
    • 初始化一个变量 additional_cost 来记录需要增加的价格总和。
  2. 遍历价格序列

    • 对于每个月的价格 p[i],计算当前的上涨系数 current_ratio,即 p[i] / total_sum
    • 如果 current_ratio 超过了 k%,则需要调整当前月份的价格。
  3. 调整价格

    • 计算需要增加的价格 needed_increase,使得 current_ratio 不超过 k%
    • 更新 additional_cost 和 total_sum
  4. 返回结果

    • 返回 additional_cost 作为最终结果。

解题过程

  1. 二分查找初始化:我们初始化二分查找的左右边界,左边界l为0,右边界r为一个很大的数(例如109)。
  2. 二分查找过程:在每次循环中,我们计算中间值mid,并判断在增加mid价格的情况下,是否所有月份的上涨系数都不超过k%。
  3. **判断函数ok**:这个函数用于判断在增加x价格的情况下,是否所有月份的上涨系数都不超过k%。具体来说,我们计算每个月的价格总和,并检查每个月的上涨系数是否满足条件。
  4. 调整边界:如果当前的mid满足条件,则说明可能存在更小的增加价格,因此我们将右边界r调整为mid;否则,我们将左边界l调整为mid + 1
  5. 返回结果:最终,当l等于r时,l即为最小的增加价格总和。

复杂度分析

  • 时间复杂度:二分查找的时间复杂度为O(log(109)),每次判断的时间复杂度为O(n),因此总的时间复杂度为O(nlog(109))。
  • 空间复杂度:除了输入数组外,我们只使用了常数级别的额外空间,因此空间复杂度为O(1)。

知识点扩展

  • 二分查找:二分查找是一种高效的查找算法,适用于在有序数组中查找特定值或满足特定条件的值。在本题中,我们通过二分查找来找到最小的增加价格总和。
  • 贪心算法:虽然本题没有直接使用贪心算法,但贪心算法的思想在判断函数ok中有所体现,即我们每次都尽量满足条件,而不考虑全局最优。

代码实现

Python
def solution(n:int, k:int, p:list)->int:
    assert n == len(p)

    def ok(x, n, k, a):
        s = x + a[0]
        for i in range(1, n):
            if 100 * a[i] > s * k:
                return False
            s += a[i]
        return True

    l, r = 0, int(1e9)
    while l < r:
        mid = (l + r) // 2
        if ok(mid, n, k, p):
            r = mid
        else:
            l = mid + 1
    return l


if __name__ == '__main__':
    print(solution(n = 5,k = 12,p = [1000, 34, 12, 27, 131]) == 19)
    print(solution(n = 4,k = 10,p = [100, 1, 1, 1]) == 0)
    print(solution(n = 6,k = 15,p = [500, 50, 30, 20, 10, 60]) == 0)
C++
#include <iostream>
#include <vector>

int solution(int n, int k, std::vector<int>& p) {
    assert(n == p.size());

    auto ok = [](int x, int n, int k, const std::vector<int>& a) -> bool {
        int s = x + a[0];
        for (int i = 1; i < n; ++i) {
            if (100 * a[i] > s * k) {
                return false;
            }
            s += a[i];
        }
        return true;
    };

    int l = 0, r = 1e9;
    while (l < r) {
        int mid = (l + r) / 2;
        if (ok(mid, n, k, p)) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}

int main() {
    std::vector<int> arr1 = {1000, 34, 12, 27, 131};
    std::vector<int> arr2 = {100, 1, 1, 1};
    std::vector<int> arr3 = {500, 50, 30, 20, 10, 60};

    std::cout << (solution(5, 12, arr1) == 19) << std::endl;
    std::cout << (solution(4, 10, arr2) == 0) << std::endl;
    std::cout << (solution(6, 15, arr3) == 0) << std::endl;
    return 0;
}

关键步骤解释

  1. **函数 solution**:

    • 参数 n 表示月份的数量,k 表示上涨系数的百分比,p 是价格序列。
    • 使用 assert 确保 n 等于 p 的长度。
  2. **Lambda 函数 ok**:

    • 用于检查在增加 x 的价格后,是否所有月份的上涨系数都不超过 k%
    • 初始化 s 为 x + a[0],然后遍历价格序列,检查每个价格是否满足条件。
  3. 二分查找

    • 初始化 l 为 0,r 为 1e9
    • 使用二分查找来找到最小的 x,使得 ok(x, n, k, p) 为 true
  4. **主函数 main**:

    • 定义测试样例并调用 solution 函数进行测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值