(A卷,200分)- 开放日活动、取出尽量少的球(Java & JS & Python)

题目描述

某部门开展Family Day开放日活动,其中有个从桶里取球的游戏,游戏规则如下:

有N个容量一样的小桶等距排开,

且每个小桶都默认装了数量不等的小球,

每个小桶装的小球数量记录在数组 bucketBallNums 中,

游戏开始时,要求所有桶的小球总数不能超过SUM,

如果小球总数超过SUM,则需对所有的小桶统一设置一个容量最大值 maxCapacity,

并需将超过容量最大值的小球拿出来,直至小桶里的小球数量小于 maxCapacity;

请您根据输入的数据,计算从每个小桶里拿出的小球数量。

限制规则一:

所有小桶的小球总和小于SUM,则无需设置容量值maxCapacity,并且无需从小桶中拿球出来,返回结果[]

限制规则二:

如果所有小桶的小球总和大于SUM,则需设置容量最大值maxCapacity,并且需从小桶中拿球出来,返回从每个小桶拿出的小球数量组成的数组;

输入描述

第一行输入2个正整数,数字之间使用空格隔开,其中第一个数字表示SUM,第二个数字表示bucketBallNums数组长度;
第二行输入N个正整数,数字之间使用空格隔开,表示bucketBallNums的每一项;

输出描述

找到一个maxCapacity,来保证取出尽量少的球,并返回从每个小桶拿出的小球数量组成的数组。

备注

  • 1 ≤ bucketBallNums[i] ≤ 10^9
  • 1 ≤ bucketBallNums.length = N ≤ 10^5
  • 1 ≤ maxCapacity ≤ 10^9
  • 1 ≤ SUM ≤ 10^9

用例

输入 14 7
2 3 2 5 5 1 4
输出 [0,1,0,3,3,0,2]
说明 小球总数为22,SUM=14,超出范围了,需从小桶取球,
maxCapacity=1,取出球后,桶里剩余小球总和为7,远小于14
maxCapacity=2,取出球后,桶里剩余小球总和为13,
maxCapacity=3,取出球后,桶里剩余小球总和为16,大于14
因此maxCapacity为2 ,每个小桶小球数量大于2的都需要拿出来;
输入 3 3
1 2 3
输出 [0,1,2]
说明 小球总数为6,SUM=3,超出范围了,需从小桶中取球,maxCapacity=1,则小球总数为3,从1号桶取0个球,2号桶取1个球,3号桶取2个球;
输入 6 2
3 2
输出 []
说明 小球总数为5,SUM=6,在范围内,无需从小桶取球;

题目解析

用例示意图如下:

由于所有桶中的球数之和超过了14,因此我们需要设置一个maxCapacity来限制每个桶中球的数量。

如果maxCapacity值设置为0,则所有桶中的球都需要取出,因此剩余球总数为0,小于sum=14,因此符合要求

如果maxCapacity值设置为1,则所有桶中的球最多只保留1个,如下图所示,剩余球总数7个,也符合要求

如果maxCapacity值设置为2,则所有桶中的球最多只保留2个,如下图所示,剩余球总数13个,也符合要求

如果maxCapacity值设置为3,则所有桶中的球最多只保留3个,如下图所示,剩余球总数17个,不符合要求

因此,我们可以发现,maxCapacity取值2时,剩余球数最多,总数量小于SUM=14,符合要求,且取出的球最少,分别为0,1,0,3,3,0,2。

那么我们是否需要从maxCapacity=0开始找呢?

答案是不需要,我们完全可以使用 SUM / bucketBallNums.length 求得一个最理想值.

比如用例中SUM=14,bucketBallNums.length=7,则每个桶中球数量的最理想值是14/7=2。

我们可以将此时最理想值作为maxCapacity的起始值。然后向后查找。

但是上面这种算法在应对较大数量级,可能会超时,因此改进策略是使用二分查找,具体逻辑请看

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 2) {
    const [sum, n] = lines[0].split(" ").map(Number);
    const arr = lines[1].split(" ").map(Number);
    console.log(getResult(sum, arr, n));
    lines.length = 0;
  }
});

function getResult(sum, arr, n) {
  const total = arr.reduce((p, c) => p + c);

  if (total <= sum) return "[]";

  let max_maxCapacity = Math.max.apply(null, arr);
  let min_maxCapacity = Math.floor(sum / n);

  // ans保存题解,初始题解为min_maxCapacity对应的题解
  let ans = arr.map((count) =>
    count > min_maxCapacity ? count - min_maxCapacity : 0
  );

  while (max_maxCapacity - min_maxCapacity > 1) {
    const maxCapacity = Math.floor((max_maxCapacity + min_maxCapacity) / 2);

    let remain = total;

    // tmp数组保存的是每个桶移除的球的数量
    const tmp = arr.map((count) => {
      // r是每个桶需要移除的球的个数,如果桶内球数超过maxCapacity,则需要移除超出部分,否则不需要移除
      const r = count > maxCapacity ? count - maxCapacity : 0;
      remain -= r;
      return r;
    });

    if (remain > sum) {
      max_maxCapacity = maxCapacity;
    } else if (remain < sum) {
      min_maxCapacity = maxCapacity;
      ans = tmp;
    } else {
      ans = tmp;
      break;
    }
  }

  return JSON.stringify(ans);
}

Java算法源码

考虑total会超过int范围,所以total设置为long类型。以及remain也设置为long类型。

import java.util.Arrays;
import java.util.Scanner;
import java.util.StringJoiner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    int sum = sc.nextInt();
    int n = sc.nextInt();

    Integer[] arr = new Integer[n];
    for (int i = 0; i < n; i++) {
      arr[i] = sc.nextInt();
    }

    System.out.println(getResult(sum, arr, n));
  }

  public static String getResult(int sum, Integer[] arr, int n) {
    long total = 0;
    int max_maxCapacity = 0;
    for (int i = 0; i < n; i++) {
      max_maxCapacity = Math.max(max_maxCapacity, arr[i]);
      total += arr[i];
    }

    if (total <= sum) return "[]";

    int min_maxCapacity = sum / n;

    final int min_maxCapacity_copy = min_maxCapacity;
    Integer[] ans =
        Arrays.stream(arr)
            .map(count -> count > min_maxCapacity_copy ? count - min_maxCapacity_copy : 0)
            .toArray(Integer[]::new);

    while (max_maxCapacity - min_maxCapacity > 1) {
      int maxCapacity = (max_maxCapacity + min_maxCapacity) / 2;

      // tmp数组保存的是每个桶移除的球的数量
      Integer[] tmp = new Integer[n];
      long remain = total;
      for (int i = 0; i < arr.length; i++) {
        // r是每个桶需要移除的球的个数,如果桶内球数超过maxCapacity,则需要移除超出部分,否则不需要移除
        int r = arr[i] > maxCapacity ? arr[i] - maxCapacity : 0;
        remain -= r;
        tmp[i] = r;
      }

      if (remain > sum) {
        max_maxCapacity = maxCapacity;
      } else if (remain < sum) {
        min_maxCapacity = maxCapacity;
        ans = tmp;
      } else {
        ans = tmp;
        break;
      }
    }

    StringJoiner sj = new StringJoiner(",", "[", "]");
    for (Integer an : ans) {
      sj.add(an + "");
    }

    return sj.toString();
  }
}

Python算法源码

# 输入获取
sumV, n = map(int, input().split())
arr = list(map(int, input().split()))


# 算法入口
def getResult(sumV, arr, n):
    total = sum(arr)

    if total <= sumV:
        return "[]"

    max_maxCapacity = max(arr)
    min_maxCapacity = int(sumV / n)

    # ans保存题解,初始题解为min_maxCapacity对应的题解
    ans = list(map(lambda count: count - min_maxCapacity if count > min_maxCapacity else 0, arr))

    while max_maxCapacity - min_maxCapacity > 1:
        maxCapacity = int((max_maxCapacity + min_maxCapacity) / 2)

        # tmp数组保存的是每个桶移除的球的数量
        tmp = list(map(lambda count: count - maxCapacity if count > maxCapacity else 0, arr))

        remain = total - sum(tmp)
        if remain > sumV:
            max_maxCapacity = maxCapacity
        elif remain < sumV:
            min_maxCapacity = maxCapacity
            ans = tmp
        else:
            ans = tmp
            break

    return "[" + ",".join(map(str, ans)) + "]"


# 调用算法
print(getResult(sumV, arr, n))

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?