问题
问题描述
在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。规则如下:
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。
小R想知道,为了公平地满足所有猫的等级差异,他至少需要准备多少斤鱼干。
测试样例
样例1:
输入:
n = 3, cats_levels = [1, 2, 2]输出:4
样例2:
输入:
n = 6, cats_levels = [6, 5, 4, 3, 2, 16]输出:17
样例3:
输入:
n = 20, cats_levels = [1, 2, 2, 3, 3, 20, 1, 2, 3, 3, 2, 1, 5, 6, 6, 5, 5, 7, 7, 4]输出:35
解题思路
解决方法:两次遍历
如果一下子想要确定这只猫要分配多少鱼干比较困难的话,我们可以先将这个问题拆解为两个问题。
问题1规则如下
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它左边相邻的猫,它就应该得到比左边相邻的猫更多的鱼干。
那很简单,我们只要从左往右遍历,我们就能知道这只猫与左边相邻的猫之间的等级大小关系,如果这只猫等级更高,只要比左边相邻的猫获得的鱼干多1即可。
for (int i = 1; i < len; i++)
if (catsLevels[i] > catsLevels[i-1]) fish[i] = fish[i-1] + 1;
问题2规则如下
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它右边相邻的猫,它就应该得到比右边相邻的猫更多的鱼干。
那很简单,我们只要从右往左遍历,我们就能知道这只猫与右边相邻的猫之间的等级大小关系,如果这只猫等级更高,只要比右边相邻的猫获得的鱼干多1即可。
for (int i = len-2; i >= 0; i--)
if (catsLevels[i] > catsLevels[i+1] && fish[i] <= fish[i+1]) fish[i] = fish[i+1] + 1;
问题合并(原题)
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。
只需要简单的将上面两个问题的解法组合在一起即可。
for (int i = 1; i < len; i++)
if (catsLevels[i] > catsLevels[i-1]) fish[i] = fish[i-1] + 1;
for (int i = len-2; i >= 0; i--)
if (catsLevels[i] > catsLevels[i+1] && fish[i] <= fish[i+1]) fish[i] = fish[i+1] + 1;
问:第二次遍历会影响到第一次吗?
不会
在第二次遍历(从右到左)中,只有在满足以下条件时才会更新 fish[i]:
- 当前猫的等级
catsLevels[i]高于右边的猫catsLevels[i + 1]。 - 当前猫的鱼干数量
fish[i]小于或等于右边猫的鱼干数量fish[i + 1]。
这意味着,只有当 fish[i] <= fish[i + 1] 时,才会修改 fish[i]。然而,这种情况下,fish[i] 的值会被调整为 fish[i + 1] + 1。这样做不会影响到 fish[i] 和左边相邻猫的关系,因为:
- 如果
fish[i]在第一次遍历中已经比fish[i - 1]大(即fish[i] > fish[i - 1]),那么第二次遍历时,fish[i]的值只可能增加,不会减小,因此fish[i] > fish[i - 1]仍然成立。 - 如果
fish[i]在第一次遍历中不比fish[i - 1]大,第二次遍历时对fish[i]的增加也不会影响fish[i - 1],因为我们接下来就会对fish[i-1]进行判断和修正。
Code
#include <iostream>
#include <vector>
int solution(int n, std::vector<int> catsLevels) {
// Please write your code here
int len = catsLevels.size();
std::vector<int> fish(len, 1);
for (int i = 1; i < len; i++)
if (catsLevels[i] > catsLevels[i-1]) fish[i] = fish[i-1] + 1;
for (int i = len-2; i >= 0; i--)
if (catsLevels[i] > catsLevels[i+1] && fish[i] <= fish[i+1]) fish[i] = fish[i+1] + 1;
int ans = 0;
for (int i = 0; i < len; i++) ans += fish[i];
return ans;
}
int main() {
std::vector<int> catsLevels1 = {1, 2, 2};
std::vector<int> catsLevels2 = {6, 5, 4, 3, 2, 16};
std::vector<int> catsLevels3 = {1, 2, 2, 3, 3, 20, 1, 2, 3, 3, 2, 1, 5, 6, 6, 5, 5, 7, 7, 4};
std::cout << (solution(3, catsLevels1) == 4) << std::endl;
std::cout << (solution(6, catsLevels2) == 17) << std::endl;
std::cout << (solution(20, catsLevels3) == 35) << std::endl;
return 0;
}
时间复杂度分析
- 空间复杂度:代码使用了一个大小为
len的fish数组来存储每只猫所需的鱼干数量,len是输入catsLevels的大小。因此,空间复杂度为O(N)。 - 时间复杂度:两次遍历计算
fish,以及最后一次遍历fish计算总和,时间复杂度为O(N)