雪糕的最大数量
商店中新到 n 支雪糕,用长度为 n 的数组 costs 表示雪糕的定价,其中 costs[i] 表示第 i 支雪糕的现金价格。Tony 一共有 coins 现金可以用于消费,他想要买尽可能多的雪糕。
给你价格数组 costs 和现金量 coins ,请你计算并返回 Tony 用 coins 现金能够买到的雪糕的 最大数量 。
注意:Tony 可以按任意顺序购买雪糕,每个雪糕只能买一次。
示例 1:
输入:costs = [1,3,2,4,1], coins = 7
输出:4
解释:Tony 可以买下标为 0、1、2、4 的雪糕,总价为 1 + 3 + 2 + 1 = 7
解法1:先排序再顺序购买(初步想法),代码如下。遇到问题,数据量大时,快排超时。
class Solution {
public int maxIceCream(int[] costs, int coins) {
if(coins <= 0){
return 0;
}
quickSort(costs, 0, costs.length-1);
int result = 0;
int sum = 0;
for(int i = 0; i < costs.length; ++i){
sum += costs[i];
if(sum <= coins){
result++;
}else{
break;
}
}
return result;
}
private void quickSort(int[] arr, int i, int j){
if(i >= j){
return;
}
int index = partSort(arr, i, j);
quickSort(arr, i, index-1);
quickSort(arr, index+1, j);
}
private int partSort(int[] arr, int beg, int end){
int left = beg;
int right = end;
int key = arr[end];
while(left < right){
while(left < right && arr[left] <= key){
left++;
}
while(left < right && arr[right] >= key){
right--;
}
if(left < right){
swap(arr, left, right);
}
}
swap(arr, left, end);
return left;
}
private void swap(int[] arr, int left, int right){
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
解法2:数据元素太大,基于快排超时,使用推排序,获取前n个最小值,提交成功。
class Solution {
public int maxIceCream(int[] costs, int coins) {
if (coins <= 0 || costs.length <= 0) {
return 0;
}
if (costs.length > 1) {
createHeap(costs, costs.length);
}
//此时数据costs[0]是最小堆的堆顶元素
int result = 0;
int sum = 0;
for (int i = 0; i < costs.length; ++i) {
sum += costs[0];
if (sum <= coins) {
result++;
} else {
break;
}
//删除堆顶元素,放置数组最后一个,再循环调整堆
swap(costs, 0, costs.length - i - 1);
adjustDown(costs, costs.length - i - 1, 0);
}
return result;
}
//建堆方法
private static void createHeap(int[] array, int size) {
// 下沉式调整, 需要从后往前遍历,
// 从最后一个非叶子节点开始遍历
// size - 1表示最后一个元素的下标
// 拿着这个下标 - 1 / 2 就得到了当前元素的父节点
for (int i = (size - 2) / 2; i >= 0; --i) {
adjustDown(array, size, i);
}
}
// 向下调整
private static void adjustDown(int[] array, int size, int parent) {
int leftChild = 2 * parent + 1;// 左子树
int rightChild = 2 * parent + 2;
int minChild;
if (leftChild >= size) {
return;
}
minChild = leftChild;
if (rightChild < size && array[rightChild] < array[leftChild]) {
minChild = rightChild;// 找出左右孩子的最小值
}
if (array[parent] < array[minChild]) {// 满足堆条件
return;
}
swap(array, parent, minChild);
adjustDown(array, size, minChild);
}
private static void swap(int[] array, int num1, int num2) {
int tmp = array[num1];
array[num1] = array[num2];
array[num2] = tmp;
}
}