分配鱼干问题 | 豆包MarsCode AI刷题

86 阅读6分钟

一、题目概述

在这个问题中,我们需要分配鱼干给一群猫,每只猫的等级可能不同。我们需要按下边的分配制度进行分配:

  1. 每只猫至少获得 1 斤鱼干。
  2. 如果一只猫的等级比它的邻居高,那么它必须获得比邻居更多的鱼干。

给定了猫的数量和它们的等级信息,要求我们计算出满足这些条件的鱼干最小分配总数。

二、问题分析

我们分析过问题后可以拆解为以下几个方面:

  1. 分配最小鱼干数:每只猫最少需要 1 斤鱼干。
  2. 等级约束:如果一只猫的等级比它的相邻猫高,它必须得到更多的鱼干。 3.最小单位:鱼干分配的最小单位为斤,且只能为整数。

解法思路

我们可以通过贪心算法与动态规划的结合来解决这个问题。要考虑以下两个方面的遍历:

  • 从左到右的遍历:如果当前猫的等级大于左边猫邻居的等级,那么它的鱼干数应该比邻居多 1。
  • 从右到左的遍历:同样地,如果当前猫的等级大于右边猫邻居的等级,那么它的鱼干数也应该比邻居多 1。 通过这两次遍历,我们就可以确保每只猫的鱼干数都满足要求。

步骤详解

  1. 初始化鱼干数组:我们首先初始化一个数组 fish,用来存储每只猫获得的鱼干数量。所有元素初始化为 1,因为每只猫至少需要 1 斤鱼干。

  2. 左到右遍历:我们遍历猫的等级数组,从左到右。如果发现当前猫的等级大于前一只猫的等级,则将当前猫的鱼干数设置为前一只猫鱼干数的基础上增加 1。

  3. 右到左遍历:接着,我们从右到左遍历猫的等级数组。如果当前猫的等级比它右边的猫高,我们需要确保它的鱼干数大于右边猫的鱼干数。如果在左到右遍历时已经分配过更多的鱼干,此时我们保留较大的值。

  4. 计算总鱼干数:最后,我们求出所有猫所需鱼干的总和,即所有鱼干数之和。

动态规划与贪心算法结合

  • 动态规划:这种方法主要用于解决最优子结构的问题。在本问题中,fish[i] 的计算依赖于前一个猫和后一个猫的等级关系。这就是动态规划的思想:逐步构建问题的解。
  • 贪心算法:在每次遍历时,我们局部做出最优选择(即保证鱼干数递增),确保整个过程符合条件。

三、代码实现

function solution(n, cats_levels) {
    // 初始化鱼干数量数组每只猫最少1斤鱼干
    let fish = new Array(n).fill(1);
    // 从左到右遍历确保等级高的猫鱼干更多
    for (let i = 1; i < n; i++) {
        if (cats_levels[i] > cats_levels[i - 1]) {
            fish[i] = fish[i - 1] + 1;
        }
    }
    // 从右到左遍历
    for (let i = n - 2; i >= 0; i--) {
        if (cats_levels[i] > cats_levels[i + 1]) {
            fish[i] = Math.max(fish[i], fish[i + 1] + 1);
        }
    }
    // 返回所有猫所需鱼干的总和
    return fish.reduce((total, fishCount) => total + fishCount, 0);
}

代码解释

  1. 初始化:fish数组记录每只猫的鱼干数。初始化时,每只猫的鱼干数为 1。

  2. 左到右遍历:如果当前猫的等级比前一只猫高,则它的鱼干数要比前一只猫多 1。

  3. 右到左遍历:如果当前猫的等级比右边的猫高,则它的鱼干数至少要比右边猫的鱼干数多 1。

  4. 计算结果:最终返回 fish 数组所有元素的和,即所有猫所需的最少鱼干数。

复杂度分析

  • 时间复杂度:左到右遍历需要 O(N) 时间,右到左遍历也需要 O(N) 时间。总体时间复杂度为 O(N)。

  • 空间复杂度:我们额外使用了一个大小为 N 的数组 fish 来存储每只猫的鱼干数,所以空间复杂度为 O(N)。

四、知识点扩展

  1. 贪心算法:贪心算法是一种求解最优化问题的策略,它在每一步选择中都采取当前状态下最好或最优的选择。它的核心思想是局部最优解可以带来全局最优解。在本题中,保证每一只猫的鱼干数最小且满足等级约束,便是贪心策略的体现。

  2. 动态规划:动态规划是一种将问题分解成子问题并逐步求解的策略。我们在本题中,通过两次遍历来处理每一只猫的鱼干数,就可以避免重复计算,从而提高了效率。

  3. 最优子结构:这是动态规划的一个关键特征。在本问题中,fish[i] 的最优值依赖于 fish[i-1]fish[i+1],即当前决策(鱼干数)与前后猫的状态相关联。

  4. 数学归纳法:归纳法是一种常用的证明方法,可以用于证明算法的正确性。在贪心算法和动态规划的结合中,归纳法可以帮助我们证明“每个步骤都做出局部最优选择会得到全局最优解”。

五、总结

这个问题的解决方法结合了贪心算法与动态规划的优势,形成了一种高效的解决方案。通过两次遍历,第一次从左到右进行调整,确保每只猫在满足左边约束的情况下获取合适的鱼干数;第二次从右到左遍历,确保每只猫在满足右边约束的情况下重新调整其鱼干数。通过这种双向调整策略,我们能够保证每只猫的鱼干数既符合局部的贪心条件,又能兼顾整体的全局约束,从而找到一个符合要求的最优解。这个方法的核心在于结合了贪心策略的局部优化和动态规划的全局规划。贪心算法的部分确保每次选择是局部最优的,而动态规划的部分则确保我们能够跨越多个子问题,将每个局部最优解有效地结合成全局最优解。两者的结合使得我们能够在保证每个约束条件得到满足的同时,避免了暴力枚举带来的计算复杂度。

掌握这种解法,不仅能帮助我们解决类似的分配问题,还能让我们更深入地理解贪心算法与动态规划的应用场景。在实际问题中,很多时候我们需要同时关注局部和全局的约束条件,而这种结合方式为我们提供了一种灵活且高效的解决思路,在复杂问题中找到有效的解法。这种方法也不仅适用于鱼干分配问题,还可以推广到其他类似的分配、优化问题中,具有很高的实用价值。