概述
1. 问题描述:
给你一个整数数组 beans ,其中每个整数表示一个袋子里装的魔法豆的数目。请你从每个袋子中拿出一些豆子(也可以不拿出),使得剩下的非空袋子中(即至少还有一颗魔法豆的袋子)魔法豆的数目相等 。一旦魔法豆从袋子中取出,你不能将它放到任何其他的袋子中。请你返回你需要拿出魔法豆的最少数目。
示例 1:
输入:beans = [4,1,6,5]
输出:4
解释:
- 我们从有 1 个魔法豆的袋子中拿出 1 颗魔法豆。
剩下袋子中魔法豆的数目为:[4,0,6,5]
- 然后我们从有 6 个魔法豆的袋子中拿出 2 个魔法豆。
剩下袋子中魔法豆的数目为:[4,0,4,5]
- 然后我们从有 5 个魔法豆的袋子中拿出 1 个魔法豆。
剩下袋子中魔法豆的数目为:[4,0,4,4]
总共拿出了 1 + 2 + 1 = 4 个魔法豆,剩下非空袋子中魔法豆的数目相等。
没有比取出 4 个魔法豆更少的方案。
示例 2:
输入:beans = [2,10,3,2]
输出:7
解释:
- 我们从有 2 个魔法豆的其中一个袋子中拿出 2 个魔法豆。
剩下袋子中魔法豆的数目为:[0,10,3,2]
- 然后我们从另一个有 2 个魔法豆的袋子中拿出 2 个魔法豆。
剩下袋子中魔法豆的数目为:[0,10,3,0]
- 然后我们从有 3 个魔法豆的袋子中拿出 3 个魔法豆。
剩下袋子中魔法豆的数目为:[0,10,0,0]
总共拿出了 2 + 2 + 3 = 7 个魔法豆,剩下非空袋子中魔法豆的数目相等。
没有比取出 7 个魔法豆更少的方案。
提示:
1 <= beans.length <= 10 ^ 5
1 <= beans[i] <= 10 ^ 5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/removing-minimum-number-of-magic-beans/
2. 思路分析:
因为需要使得剩余袋子的豆子数量相等所以只能够将当前其余袋子的豆子的数量与袋子中豆子数量最少的豆子数量相等,基于这个想法我们可以先对beans排序,我们可以枚举将前i个袋子的豆子拿掉,然后使得剩余袋子中豆子的数量相等,i从0~n-1,因为需要将前i个袋子的豆子拿掉所以需要维护beans的前缀和s2,并且需要求解使得剩余袋子的豆子数量相等求解对应的操作次数,我们可以维护前缀和s1,其中s1[i]表示前i个数字变为第一个数字的操作次数,这样每一个元素都是以第一个袋子的豆子为基准,这样后面我们使得第i个位置之后剩余袋子中的豆子数量相等的时候减去剩余袋子数量 * (beans[i + 1] - bean[0]),并且还需要减去前i个位置变为第一个位置豆子数量的操作次数,因为我们是直接拿掉前i个位置的豆子所以这一部分的值需要减掉,所以枚举拿掉前i个袋子的豆子使得剩余袋子中豆子数量相等操作次数为:s2[i+1] + s1[n-1] - s1[i] - (n-i-1)*(beans[i+1]-beans[0]),并且还需要特判一下特殊情况:将所有元素变为第一个元素的操作次数,所有情况取一个min就是答案。
3. 代码如下:
go:
package main
import (
"fmt"
"sort"
)
// 求解两个int数字的最小值
func getMin(a, b int) int {
if a < b {
return a
}
return b
}
func minimumRemoval(beans []int) int64 {
sort.Ints(beans)
n := len(beans)
// 声明切片s1, s2这样不用声明数组那样需要固定长度, 其中s1[i]表示将0~i的数字变为第一个数字操作次数, s2[i]表示0~i-1的beans的前缀和
s1, s2 := make([]int, n+10), make([]int, n+10)
x := 0
for i := 1; i < n; i++ {
x += beans[i] - beans[i-1]
s1[i] += s1[i-1] + x
s2[i] += s2[i-1] + beans[i-1]
}
s2[n] += s2[n-1] + beans[n-1]
// 特殊情况
res := s2[n]-beans[0]*n
for i := 0; i < n-1; i++ {
// 枚举将前i个数字拿掉, 其余数字变为相等, 因为要变为相等肯定是将其余数字变为第i + 1个数字, 使用公式结合之前维护的s1, s2的值计算出其余数字变为bean[i + 1]的操作次数, 所有情况取一个min就是答案
t := s2[i+1] + s1[n-1] - s1[i] - (n-i-1)*(beans[i+1]-beans[0])
res = getMin(res, t)
}
return int64(res)
}
python:
from typing import List
class Solution:
def minimumRemoval(self, beans: List[int]) -> int:
n = len(beans)
beans.sort()
s1, s2 = [0], [0]
x = 0
for i in range(1, n):
x += beans[i] - beans[i - 1]
s1.append(s1[i - 1] + x)
s2.append(s2[-1] + beans[i - 1])
# 计算最后一个位置的前缀和
s2.append(s2[-1] + beans[-1])
res = s2[-1] - beans[0] * n
for i in range(n - 1):
res = min(res, s2[i + 1] - s1[i] + s1[n - 1] - (n - i - 1) * (beans[i + 1] - beans[0]))
return res
最后
以上就是糟糕短靴为你收集整理的2171 拿出最少数目的魔法豆(枚举 + 前缀和)的全部内容,希望文章能够帮你解决2171 拿出最少数目的魔法豆(枚举 + 前缀和)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复