一、题目
拿出最少的魔法豆
二、代码
没做出来呜呜😢
// 思路是想要找到一个最后非空魔法袋中的魔法豆的数量,之后将小于其的全部拿走,大于的将多余部分拿走;但思考半天没想出要如何挑选这个数值,下面是错误尝试用中位数代替分割数
class Solution {
public long minimumRemoval(int[] beans) {
// 0
ArrayList<Integer> list = new ArrayList<Integer>();
Collections.addAll(list, Arrays.stream(beans).boxed().toArray(Integer[]::new));
Collections.sort(list);
int len = beans.length;
int mid = (list.get(0)+list.get(len-1))/2;
long res = 0;
for(int i=0;i<len;i++) {
if(beans[i] < mid) {
res = res + beans[i];
}else if(beans[i] > mid) {
res = res + (beans[i]-mid);
}
}
return res;
}
}
// 在我重新整理过程中才发现这个“分割数”一定为beans数组中的一个,因为小于它的肯定都要去掉,只有选择beans数组中的一个,才会使得大于它的元素和它的差值最小
// 另外需要补充注释0的3行代码本来是想要实现将数组排序,因为不知道可以使用Arrays.sort(beans);从而麻烦的将其转换为Array然后又进行的排序(呜呜呜~好笨笨😢)
三、题解
思路
我们最后要达到的最终状态是除了0以外,其他所有豆子都一样的数目,假设这个数目为k。
每个袋子里有两种情况:
袋子原来豆子数目bean < k,此时该袋子里豆子要被全部拿走,拿走数目为bean。
袋子原来豆子数目bean > k,此时该袋子里豆子要被拿走bean - k。
解法
先排序,我们会发现当k是beans数组里本来就有的数字时,拿走的魔法豆会更小,而当k=beans[i]的时候,下标小于i的所有袋子,全部拿走,下标大于i的袋子,拿走到只有bean[i]个豆子。所以剩下的豆子如图所示:
先排序,我们会发现当k是beans数组里本来就有的数字时,拿走的魔法豆会更小,而当k=beans[i]的时候,下标小于i的所有袋子,全部拿走,下标大于i的袋子,拿走到只有bean[i]个豆子。所以剩下的豆子如图所示:
因此我们进行一次遍历,计算出k=beans[i]的时候需要拿走的豆子数量就是豆子总数减掉图里蓝色长方形部分:total - beans[i] * (n - i)(这里n-i可通过具体例子验证,如i取0,即没有任何一个袋子里的豆需要被全部拿走,此时n-0=n正好是整个数组长度),遍历时维护一个值res,保存最小需要拿走的魔法豆数量即可。
代码
class Solution {
public long minimumRemoval(int[] beans) {
int n = beans.length;
Arrays.sort(beans);
long sum = 0;
for(int j = 0; j < n; j++){
sum += beans[j];
}
long temp = 0;
long ans = sum;
for(int i = 0; i < n; i++){
// beans[i]是int32,因此必须加1L
temp = sum - 1L * (n-i) * beans[i];
if(temp<ans) ans = temp;
}
return ans;
}
}
来源:力扣(LeetCode)
四、总结
其他:
① int数组排序使用Arrays.sort(int []n);
② 重新敲一遍的时候发现 temp = sum - 1L * (n-i) * beans[i]; 这里int转long要在前面乘1L