朝花夕拾

A Development Engineer, a Life Liver, a Hope Holder

问题

有一批货,体积大小随机,有一批箱子,体积固定为3,不考虑货物的体积,求给定货物最多能装满几个箱子。

说明:体积为6的货物可以用2个箱子装完,体积为7的箱子不能被箱子装下

思路

当货物的体积为3的整数倍时,货物可以刚好装满箱子
当货物总体积除以3余1时,说明至少存在一个体积除3余1的货物,剔除其中最小的一个即可。
当货物体积除以3余2时,说明可能存在偶数个除3与1的货物或奇数个除3余2的货物。剔除2个最小除3余1的货物
或者剔除最小的一个除3余2的货物即可。
伪代码:

// 按顺序保存最小的除3余1两个货物
int[] mode1 = int[2];

// 保存最小的除3余2的一个货物
int mode2;

// 货物总体积
int sumVolum;

if(sumVolum % 3 == 0) {
return sumVolum / 3;
}

if(sumVolum % 1 == 0) {
return (sumVolum - mode1[0])/3;
}

// 说明不存在除3余1或者不存在偶数个除3余1的货物。那么就应该剔除除3余2的货物
if(mode1[1] == 0 || mode1[1] == 0) {
return (sumVolum - mode2)/3;
}


int tmpSum = mode1[1] + mode1[1];
if(tmpSum > mode2) {
return (sumVolum - mode2)/3;
}

return (sumVolum - tmpSum)/3;

这里有个技巧,就是如何一次循环得到倒数1,2的两个最小的货物。思路是:
如果mode1[0] == 0,就先填充mode1[0]。
如果校验货物的体积比mode1[0]小,替换mode1[0]为校验货物,并将mode1[0]之间的值放置到mode1[1]
如果校验货物的提交比mode1[0]大,但是mode1[1]==0。将检验货物放置到mode1[1]。
如果校验货物的体积比mode1[0]大,但比mode1[1]小,那么将检验货物放置到mode1[1]。

代码实现

public int solution(int[] arr) {
// 分别记录除3余1和除3余2的货物
int[] mode1 = new int[2];
int mode2 = 0;

int sum = 0;

for (int i = 0; i < arr.length; i++) {
if (arr[i] % 3 == 1) {
// 一个余数为1的数都没有
if (mode1[0] == 0) {
mode1[0] = arr[i];
sum += arr[i];
continue;
}

// 将最小的放到mode1[0] 将次小的放到mode1[1]
if (mode1[0] > arr[i]) {
mode1[1] = mode1[0];
mode1[0] = arr[i];
sum += arr[i];
continue;
}

if (mode1[1] > arr[i]) {
mode1[1] = arr[i];
sum += arr[i];
continue;
}

if (mode1[1] == 0) {
mode1[1] = arr[i];
sum += arr[i];
continue;
}

}

if (arr[i] % 3 == 2) {
if (mode2 == 0) {
mode2 = arr[i];
sum += arr[i];
continue;
}

if (mode2 > arr[i]) {
mode2 = arr[i];
}
}

sum += arr[i];
}

int mode = sum % 3;
if(mode == 0) {
return sum / 3;
}

if (mode == 1) {
return (sum - mode1[0]) / 3;
}

if(mode1[0] == 0 || mode1[1] == 0) {
return (sum - mode2) / 3;
}

int nums = mode1[0] + mode1[1];
if (nums > mode2) {
return (sum - mode2) / 3;
}

return (sum - nums) / 3;
}

校验代码

int[] arr = {3, 6, 5, 1, 8};
int ret = maxBoxProblem.solution(arr);
AssertUtil.assertTrue(ret == 6, MelonStatusCodeEnums.SYSTEM_ERROR);

arr = new int[]{3, 6, 5, 1, 5, 1, 8};
ret = maxBoxProblem.solution(arr);
AssertUtil.assertTrue(ret == 9, MelonStatusCodeEnums.SYSTEM_ERROR);

arr = new int[]{5};
ret = maxBoxProblem.solution(arr);
AssertUtil.assertTrue(ret == 0, MelonStatusCodeEnums.SYSTEM_ERROR);

arr = new int[]{5, 1};
ret = maxBoxProblem.solution(arr);
AssertUtil.assertTrue(ret == 2, MelonStatusCodeEnums.SYSTEM_ERROR);

arr = new int[]{5, 1};
ret = maxBoxProblem.solution(arr);
AssertUtil.assertTrue(ret == 2, MelonStatusCodeEnums.SYSTEM_ERROR);