leetcode
leetcode 2451 ~ 2500
购买巧克力后的最小相对损失

购买巧克力后的最小相对损失

难度:

标签:

题目描述

代码结果

运行时间: 618 ms, 内存: 60.6 MB


/*
 * LeetCode 2819: Minimum Relative Loss After Buying Chocolates
 * 
 * Problem: Given an array of prices of chocolates and an integer k, we need to find the minimum relative loss
 *          if we buy exactly k chocolates. The relative loss is defined as the difference between the maximum
 *          and the minimum prices of the k chocolates purchased.
 * 
 * Approach using Java Streams:
 * 1. Sort the array of prices using Streams.
 * 2. Initialize the minimum loss to the highest possible value.
 * 3. Iterate through the sorted array, checking the relative loss for each consecutive subarray of size k.
 * 4. Update the minimum loss accordingly.
 */

import java.util.Arrays;
import java.util.stream.IntStream;

public class MinimumRelativeLossStream {
    public int minRelativeLoss(int[] prices, int k) {
        int[] sortedPrices = Arrays.stream(prices).sorted().toArray();
        return IntStream.range(0, sortedPrices.length - k + 1)
                        .map(i -> sortedPrices[i + k - 1] - sortedPrices[i])
                        .min()
                        .orElse(Integer.MAX_VALUE);
    }

    public static void main(String[] args) {
        MinimumRelativeLossStream solution = new MinimumRelativeLossStream();
        int[] prices = {5, 9, 1, 3, 8};
        int k = 3;
        System.out.println(solution.minRelativeLoss(prices, k));  // Output should be 4
    }
}

解释

方法:

此题解采用前缀和与二分搜索的方法来解决问题。首先,对价格数组进行排序,以便于后续操作。接着,计算价格数组的前缀和,这有助于快速计算任意连续子数组的和。对于每个查询,首先检查是否需要所有的巧克力,如果是,则直接计算,否则使用二分搜索确定最优的购买位置以最小化损失。二分搜索寻找使得 'k-prices[mid]' 最接近 'prices[mid + need] - k' 的位置,以确保购买的巧克力价格尽可能靠近 k。最后,结合前缀和数组,计算并返回每个查询的结果。

时间复杂度:

O(n log n + q log m)

空间复杂度:

O(n + q)

代码细节讲解

🦆
为什么在处理完全需要所有巧克力的特殊情况后,算法选择使用二分搜索而不是其他搜索方法来确定最优购买位置?
算法选择使用二分搜索而不是其他搜索方法的原因在于,数组已经被排序并且我们需要找到一个满足特定条件的点(使得损失最小化)。二分搜索是针对已排序数组的一种高效搜索方法,其时间复杂度为O(log n),远优于线性搜索的O(n)。通过二分搜索,我们可以快速定位到最接近给定条件的点,从而有效提高算法的执行效率。
🦆
在二分搜索中,如何确定`k - prices[mid] > prices[mid + need] - k`作为调整搜索范围的条件,这个条件有何数学或逻辑基础?
这个条件`k - prices[mid] > prices[mid + need] - k`是为了找到使得购买的巧克力价格尽可能接近k的位置。条件的数学基础是最小化差值的绝对值。当`k - prices[mid]`(即k与当前价格的差)大于`prices[mid + need] - k`(即当前价格与需要的价格的差)时,说明mid位置过小,需要向后搜索,从而增大mid值;反之,则说明mid位置过大,需要向前搜索,从而减小mid值。这样的逻辑可以帮助我们找到最小化差值的最佳位置。
🦆
算法在检查是否需要所有巧克力时,直接计算了一个特定表达式`psum[x] + 2 * k * (n - x) - (psum[n] - psum[x])`,这个表达式是如何得出的,它代表了什么意义?
这个表达式的计算是基于最小化损失。其中`psum[x]`代表排序后最便宜的x个巧克力的总价格,`psum[n] - psum[x]`是剩余巧克力的总价格。`2 * k * (n - x)`是如果每个巧克力的价格变为k后,剩余巧克力的总价格。因此,整个表达式`psum[x] + 2 * k * (n - x) - (psum[n] - psum[x])`代表的是在k为目标价格时,通过购买x个巧克力后计算的总损失。通过这种方式,算法尝试找到一个x值,使得总损失最小化。
🦆
前缀和数组`psum`在本题中起到了什么作用,为何必须计算前缀和而不能直接使用原始的价格数组?
前缀和数组`psum`在本题中的作用是快速计算任意连续子数组的和,这对于重复进行区间和的计算非常有效。如果使用原始的价格数组直接计算子数组的和,则每次查询的时间复杂度将是O(m),其中m是子数组的长度。使用前缀和数组后,任意子数组的和可以在O(1)时间内通过`psum[j] - psum[i]`计算得出,显著提高了效率。这在面对多个查询时尤为重要,可以有效减少整体的计算时间。

相关问题