Easy
题目描述
给你一个整数 money ,表示你拥有的钱数(以美元为单位),以及另一个整数 children ,表示你必须将钱分给孩子的数目。
你需要按照如下规则分配:
- 所有的钱都必须被分配。
- 每个人必须至少得到 1 美元。
- 没有人得到 4 美元。
如果你按照上述规则分配金钱,返回 最多 有多少个孩子可以得到 恰好 8 美元。如果无法按规则分配金钱,返回 -1 。
示例 1:
输入:money = 20, children = 3
输出:1
解释:
最多有 1 个孩子得到 8 美元。分配方案之一为:
- 给第一个孩子 8 美元。
- 给第二个孩子 9 美元。
- 给第三个孩子 3 美元。
可以证明分配方案中让得到 8 美元的孩子数目大于 1 是不可能的。
示例 2:
输入:money = 16, children = 2
输出:2
解释:每个孩子都可以得到 8 美元。
提示:
1 <= money <= 2002 <= children <= 30
解题思路
解题思路
这是一个贪心问题,我们需要在满足约束条件的前提下,最大化得到 8 美元的孩子数量。
分析约束条件
- 所有钱必须分完
- 每个孩子至少得到 1 美元
- 没有孩子得到 4 美元
贪心策略
为了最大化得到 8 美元的孩子数量,我们可以尽可能多地给孩子 8 美元,剩下的孩子给最少的钱(但不能是 4 美元)。
解法步骤
- 首先检查基础可行性:
money < children时无法满足每人至少 1 美元的要求 - 从最多可能的 8 美元孩子数开始尝试(不超过
min(money/8, children)) - 对于每个可能的 8 美元孩子数 k,检查是否能合理分配剩余的钱给其他孩子
- 剩余的钱要分给
children - k个孩子,每人至少 1 美元且不能是 4 美元
特殊情况处理
- 如果只剩一个孩子且剩余钱数为 4,这是不允许的
- 如果剩余钱数不足以给每个剩余孩子至少 1 美元,也是不可行的
通过从大到小尝试 k 值,第一个满足条件的就是答案。
代码实现
class Solution {
public:
int distMoney(int money, int children) {
// 基础检查:如果钱不够每人分1美元
if (money < children) return -1;
// 从最大可能的8美元孩子数开始尝试
int maxEight = min(money / 8, children);
for (int k = maxEight; k >= 0; k--) {
int remaining = money - k * 8;
int remainingChildren = children - k;
// 如果没有剩余孩子,剩余钱数必须为0
if (remainingChildren == 0) {
if (remaining == 0) return k;
continue;
}
// 剩余钱数必须足够给每个剩余孩子至少1美元
if (remaining < remainingChildren) continue;
// 特殊情况:如果只剩一个孩子且剩余钱为4美元,不允许
if (remainingChildren == 1 && remaining == 4) continue;
return k;
}
return -1;
}
};
class Solution:
def distMoney(self, money: int, children: int) -> int:
# 基础检查:如果钱不够每人分1美元
if money < children:
return -1
# 从最大可能的8美元孩子数开始尝试
max_eight = min(money // 8, children)
for k in range(max_eight, -1, -1):
remaining = money - k * 8
remaining_children = children - k
# 如果没有剩余孩子,剩余钱数必须为0
if remaining_children == 0:
if remaining == 0:
return k
continue
# 剩余钱数必须足够给每个剩余孩子至少1美元
if remaining < remaining_children:
continue
# 特殊情况:如果只剩一个孩子且剩余钱为4美元,不允许
if remaining_children == 1 and remaining == 4:
continue
return k
return -1
public class Solution {
public int DistMoney(int money, int children) {
// 基础检查:如果钱不够每人分1美元
if (money < children) return -1;
// 从最大可能的8美元孩子数开始尝试
int maxEight = Math.Min(money / 8, children);
for (int k = maxEight; k >= 0; k--) {
int remaining = money - k * 8;
int remainingChildren = children - k;
// 如果没有剩余孩子,剩余钱数必须为0
if (remainingChildren == 0) {
if (remaining == 0) return k;
continue;
}
// 剩余钱数必须足够给每个剩余孩子至少1美元
if (remaining < remainingChildren) continue;
// 特殊情况:如果只剩一个孩子且剩余钱为4美元,不允许
if (remainingChildren == 1 && remaining == 4) continue;
return k;
}
return -1;
}
}
var distMoney = function(money, children) {
if (money < children) return -1;
money -= children;
let eightDollarChildren = Math.min(Math.floor(money / 7), children);
let remainingMoney = money - eightDollarChildren * 7;
let remainingChildren = children - eightDollarChildren;
if (remainingChildren == 1 && remainingMoney == 3) {
eightDollarChildren--;
}
if (remainingChildren == 0 && remainingMoney > 0) {
eightDollarChildren--;
}
return eightDollarChildren;
};
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(min(money/8, children)) |
| 空间复杂度 | O(1) |
说明:
- 时间复杂度:最多需要尝试 min(money/8, children) 次,由于约束条件 money ≤ 200,children ≤ 30,所以实际复杂度很小
- 空间复杂度:只使用常数额外空间