题目解析:贪心猫的鱼干大分配 | 豆包MarsCode AI刷题

103 阅读5分钟

问题描述

在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。规则如下

1.每只猫至少得到一斤鱼干。

2.如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。

小R想知道,为了公平地满足所有猫的等级差异,他至少需要准备多少斤鱼干。

解题思路

分析:在这道题目中,我们需要确保

(1)每一只猫都有至少一个鱼干

(2)当一只猫的等级高于它左边或者右边的猫的时候,它的鱼干要比它们更多。

由问题“他至少需要准备多少斤鱼干”可以得出,我们只需要求满足条件的最少的鱼干数,因此我们只需要让高等级的猫都比旁边低等级的猫鱼干数多 1 即可。再者此题没有数据大小限制,我们可以直接进行暴力遍历与贪心算法,直到最后的鱼干分配符合上述的两个规定即可。

思路一:直接暴力+贪心算法

使用贪心算法。不断的从左到右遍历猫的数组,并确保每只猫得到的鱼干数量符合其等级要求。具体步骤如下:

  1. 初始化一个数组 fish 来存储每只猫得到的鱼干数量,初始值都设为 1,因为每只猫至少得到一斤鱼干。
  2. 从左到右不断的遍历猫的数组,对第i只猫,当它的等级比第i - 1只猫(或第i + 1只猫)的等级高,并且fish[i] <= fish[i - 1] (或fish[i] <= fish[i + 1])的时候,进行操作fish[i] = fish[i - 1] + 1 (或fish[i] =fish[i + 1] + 1
  3. 设定一个flag = 0的标记,当此次遍历无需做任何更改(即当下的鱼干分配已经符合等级要求)的时候,跳出循环
  4. 最后,计算并返回 fish 数组的总和,即为所需的最少鱼干数量。

图解:

image.png 思路二:对思路一进行简化

在思路一中,我们不断的对猫的数组进行从左到右的遍历,直至最后的结果满足等级要求,在最坏的情况下,需要进行n次才能够求出满足等级要求的鱼干数,这样复杂度过高。但是我们可以对思路一进行简化,因为对每一只高等级猫来说,我们只需要满足这只猫能够比它左边和右边的的低等级猫的鱼干数量多就行了,那我们其实只用进行两次遍历:

(1)从左到右遍历猫的数组,如果当前猫的等级高于前一只猫,则更新当前猫的鱼干数量为前一只猫的鱼干数量加一。

(2)从右到左再次遍历猫的数组,如果当前猫的等级高于后一只猫,并且当前猫的鱼干数量不大于后一只猫的鱼干数量,则更新当前猫的鱼干数量为后一只猫的鱼干数量加一。

通过测试结果可以看出,两次遍历后足以得正确答案。

图解:

image.png

完整代码

思路一:

#include <bits/stdc++.h>
using namespace std;

int solution(int n, vector<int> catsLevels) {
  // Please write your code here
  vector<int> fish(n, 1);  // 每只猫至少得到一斤鱼干
   
  int flag = 0; // 用来标记目前的鱼干数目是否符合要求
  while (1) {
    flag = 0;
    for (int i = 0; i < n; i++) {   // 从左到右依次遍历 
      if (i == 0) { // 第一只 
        if (catsLevels[0] > catsLevels[1] && fish[0] <= fish[1]) {
          fish[0] = fish[1] + 1;
          flag = 1;
        }
      } else if (i == n - 1) {  // 第二只 
        if (catsLevels[n - 1] > catsLevels[n - 2] && fish[n - 1] <= fish[n - 2]) {
          fish[n - 1] = fish[n - 2] + 1;
          flag = 1;
        }
      } else {
        if (catsLevels[i] > catsLevels[i - 1] && fish[i] <= fish[i - 1]) {
          fish[i] = fish[i - 1] + 1;
          flag = 1;
        } else if (catsLevels[i] > catsLevels[i + 1] && fish[i] <= fish[i + 1]) {
          fish[i] = fish[i + 1] + 1;
          flag = 1;
        }
      }
    }
    if(!flag) break;
  }
  
  int ans = 0;   // 记录鱼干总数 
  for(int i = 0; i < n; i++){
    ans += fish[i];
  }

  return ans;
}

int main() {
  vector<int> catsLevels1 = {1, 2, 2};
  vector<int> catsLevels2 = {6, 5, 4, 3, 2, 16};
  vector<int> catsLevels3 = {1, 2, 2, 3, 3, 20, 1, 2, 3, 3,
                                  2, 1, 5, 6, 6, 5,  5, 7, 7, 4};
  cout << (solution(3, catsLevels1) == 4) << endl;
  cout << (solution(6, catsLevels2) == 17) << endl;
  cout << (solution(20, catsLevels3) == 35) << endl;
  return 0;
}

思路二:

#include <bits/stdc++.h>
using namespace std;

int solution(int n, vector<int> catsLevels) {
  // Please write your code here
    vector<int> fish(n, 1); // 每只猫至少得到一斤鱼干

    // 从左到右遍历
    for (int i = 1; i < n; ++i) {
        // 等级 > 左边的猫
        if (catsLevels[i] > catsLevels[i - 1]) {
            fish[i] = fish[i - 1] + 1;
        }
    }

    // 从右到左遍历
    for (int i = n - 2; i >= 0; --i) {
        // 等级>右边的猫并且鱼干<=右边猫的鱼干
        if (catsLevels[i] > catsLevels[i + 1] && fish[i] <= fish[i + 1]) {
            fish[i] = fish[i + 1] + 1;
        }
    }

    // 计算所需最少鱼干数量
    int totalFish = 0;
    for (int f : fish) {
        totalFish += f;
    }

    return totalFish;
}

int main() {
  vector<int> catsLevels1 = {1, 2, 2};
  vector<int> catsLevels2 = {6, 5, 4, 3, 2, 16};
  vector<int> catsLevels3 = {1, 2, 2, 3, 3, 20, 1, 2, 3, 3,
                                  2, 1, 5, 6, 6, 5,  5, 7, 7, 4};
  cout << (solution(3, catsLevels1) == 4) << endl;
  cout << (solution(6, catsLevels2) == 17) << endl;
  cout << (solution(20, catsLevels3) == 35) << endl;
  return 0;
}

个人思考与分析

以下是几点我的学习总结:

(1)对于本道题,我感觉我个人刚开始还是想的太简单了,只想着直接不断循环就会出答案,以至于没有很快发现其实只用两次就可以得出答案,感觉自己在思考问题方面还是需要再多锻炼。

(2)最近在使用ai刷题的过程中,我觉得特别不错的一个点就是右边的ai助手了,能够协助我编写代码,比如在代码过程中,我忘记了sort函数怎么降序排序了,我就可以直接问ai,让它告诉我知识点,提高了我的学习效率。

(3)对于第一次写题解,我感觉我还有很大的不足,感觉自己写的很啰嗦,而且没有很好的表达出自己的想法,还需要多学习锻炼。

本人第一次写题目解析,如果有哪里讲的不对的或者有哪里做的不够好的,欢迎各位批评指点,非常感谢!