当前位置: 首页 > news >正文

力扣(leetcode)每日一题 2286 以组为单位订音乐会的门票 | 线段树

2286. 以组为单位订音乐会的门票

题干

一个音乐会总共有 n 排座位,编号从 0n - 1 ,每一排有 m 个座椅,编号为 0m - 1 。你需要设计一个买票系统,针对以下情况进行座位安排:

  • 同一组的 k 位观众坐在 同一排座位,且座位连续
  • k 位观众中 每一位 都有座位坐,但他们 不一定 坐在一起。

由于观众非常挑剔,所以:

  • 只有当一个组里所有成员座位的排数都 小于等于 maxRow ,这个组才能订座位。每一组的 maxRow 可能 不同
  • 如果有多排座位可以选择,优先选择 最小 的排数。如果同一排中有多个座位可以坐,优先选择号码 最小 的。

请你实现 BookMyShow 类:

  • BookMyShow(int n, int m) ,初始化对象,n 是排数,m 是每一排的座位数。
  • int[] gather(int k, int maxRow) 返回长度为 2 的数组,表示 k 个成员中 第一个座位 的排数和座位编号,这 k 位成员必须坐在 同一排座位,且座位连续 。换言之,返回最小可能的 rc 满足第 r 排中 [c, c + k - 1] 的座位都是空的,且 r <= maxRow 。如果 无法 安排座位,返回 []
  • boolean scatter(int k, int maxRow) 如果组里所有 k 个成员 不一定 要坐在一起的前提下,都能在第 0 排到第 maxRow 排之间找到座位,那么请返回 true 。这种情况下,每个成员都优先找排数 最小 ,然后是座位编号最小的座位。如果不能安排所有 k 个成员的座位,请返回 false

示例 1:

输入:
[“BookMyShow”, “gather”, “gather”, “scatter”, “scatter”]
[[2, 5], [4, 0], [2, 0], [5, 1], [5, 1]]
输出:
[null, [0, 0], [], true, false]

解释:
BookMyShow bms = new BookMyShow(2, 5); // 总共有 2 排,每排 5 个座位。
bms.gather(4, 0); // 返回 [0, 0]
// 这一组安排第 0 排 [0, 3] 的座位。
bms.gather(2, 0); // 返回 []
// 第 0 排只剩下 1 个座位。
// 所以无法安排 2 个连续座位。
bms.scatter(5, 1); // 返回 True
// 这一组安排第 0 排第 4 个座位和第 1 排 [0, 3] 的座位。
bms.scatter(5, 1); // 返回 False
// 总共只剩下 1 个座位。

提示:

  • 1 <= n <= 5 * 104
  • 1 <= m, k <= 109
  • 0 <= maxRow <= n - 1
  • gatherscatter 调用次数不超过 5 * 104 次。
题解1

这里实现的时候,我还不会线段树。硬是通过小优化使得提交通过

在这里插入图片描述

class BookMyShow {int totalRow;int[] arr;int jump = 0;long totalCount;public BookMyShow (int n, int m) {// 需要加快更新的频率arr = new int[n];totalRow = m;totalCount = (long) n * m;}public int[] gather(int k, int maxRow) {// 快速失败if (k > totalRow) {return new int[0];}for (int i = jump; i <= maxRow; i++) {// 计算是否放得下if (arr[i] + k <= totalRow) {int[] res = new int[]{i, arr[i]};arr[i] = arr[i] + k;// 没有问题totalCount -= k;return res;}}return new int[0];}public boolean scatter(int k, int maxRow) {if (totalCount < k) {return false;}int count = 0;boolean flag = false;int index = 0;for (int i = jump; i <= maxRow; i++) {count += totalRow - arr[i];if (count >= k) {flag = true;index = i;break;}}if (!flag) {return false;}// 可以省略
//        for (int i = jump; i < index; i++) {
//            arr[i] = totalRow;
//        }jump = index;// 多累计了3人,需要减去arr[index] = totalRow - (count - k);totalCount -= k;return true;}
}
题解2

这里的线段树应该不是最优解,不然这里的数值不会这么难看
但是我没有精力去精进
因为用前面题解的模板来改写
在这里插入图片描述

class Solution2286 {  public static void main(String[] args) {  BookMyShow bookMyShow = new BookMyShow(5, 9); // 假设是9个位置  bookMyShow.scatter(9, 1);  bookMyShow.scatter(1, 3);  bookMyShow.gather(3, 4);  bookMyShow.gather(1, 1);  bookMyShow.gather(10, 4);  }  static class BookMyShow {  int totalSpace;  int[] arr;  long[] sumArr;  int[] minArr;  int right;  int left = 1;  int root = 1;  public BookMyShow(int n, int m) {  right = n;  int length = n + 1;  arr = new int[length];  sumArr = new long[4 * length]; // 这里加速了范围上累加和的查询  minArr = new int[4 * length];  // 这里加速了范围上最小值的查询  totalSpace = m;  }  public int[] gather(int k, int maxRow) {  maxRow++;  int min = getMin(left, right, root, totalSpace - k);//  9 个位置 来了5个  需要找小于等于4的  if (min > maxRow) {  return new int[0];  }  // 查询当前min的值  long query = query(min, min);  // 更新当前min的值  update(min, min, (int) query + k);  return new int[]{min - 1, (int) query};  }  //  9871    9   只要找到小于9的行就可以进行增加了  public boolean scatter(int k, int maxRow) {  maxRow++;  // 计算和  long res = query(1, maxRow);  // 当这里的累计大于k的时候就可以入座  if (res + k > (long) (maxRow) * totalSpace) {  return false;  }  //  9 个位置 只要是小于9的就可以了,查询小于等于8的  int min = getMin(left, right, root, totalSpace - 1);  while (true) {  int query = (int) query(min, min);  if (query + k <= totalSpace) { // 当前排的位置可以把人安排了就安排入座  update(min, min, k + query); // 这里需要k+min  return true;  }  // 更新  update(min, min, totalSpace);  k -= (totalSpace - query);// 这里查询到4个,那么可以安排 5个入座。计算就是9-4  min = getMin(left, right, root, totalSpace - 1);  }  }  public int getMin(int left, int right, int node, int value) {  if (left == right) {  if (minArr[node] > value) {  // 没有  return Integer.MAX_VALUE;  }  return left;  }  int mid = (left + right) / 2;  if (minArr[node * 2] <= value) {  return getMin(left, mid, node * 2, value);  } else {  return getMin(mid + 1, right, node * 2 + 1, value);  }  }  public long query(int start, int end) {  return query(start, end, left, right, root);  }  public long query(int start, int end, int left, int right, int node) {  if (start <= left && right <= end) {  return sumArr[node];  }  int mid = (left + right) / 2;  long total = 0;  if (start <= mid) { // 下发左边  total += query(start, end, left, mid, node * 2);  }  if (end > mid) { // 下发右边  total += query(start, end, mid + 1, right, node * 2 + 1);  }  return total;  }  public void update(int start, int end, int value) {  update(start, end, value, left, right, root);  }  // 模板是范围上更新,但是这里的实际情况是单点更新public void update(int start, int end, int value, int left, int right, int node) {  if (start <= left && right <= end) {  sumArr[node] = value;  minArr[node] = value;  return;  }  int mid = (left + right) / 2;  if (start <= mid) { // 下发左边  update(start, end, value, left, mid, node * 2);  }  if (end > mid) { // 下发右边  update(start, end, value, mid + 1, right, node * 2 + 1);  }  // 刷新求和  sumArr[node] = sumArr[node * 2] + sumArr[node * 2 + 1];  // 刷新最小  minArr[node] = Math.min(minArr[node * 2], minArr[node * 2 + 1]);  }  }  }
总结

minArr的使用是超出了模板的范围

// 刷新求和  
sumArr[node] = sumArr[node * 2] + sumArr[node * 2 + 1];  
// 刷新最小  
minArr[node] = Math.min(minArr[node * 2], minArr[node * 2 + 1]);  

这些值的刷新,在递归前,还是递归后,还是递归方法的尽头。都是有讲究的


http://www.mrgr.cn/news/40260.html

相关文章:

  • 力扣(leetcode)每日一题 1845 座位预约管理系统| treeSet和priority Queue的区别|线段树
  • Ajax ( 是什么、URL、axios、HTTP、快速收集表单 )Day01
  • 端点安全服务:全面的端点安全解决方案
  • 多普勒频移
  • 如何选择与运用工具提升工作效率的秘密指南
  • 毕业设计选题:基于ssm+vue+uniapp的购物系统小程序
  • fNIRS光极排布——基于fNIRS Optodes’ Location Decider (fOLD)工具包
  • OkHttp 详细使用步骤,以及异步请求和同步请求
  • 深度学习:GAN图像生成
  • ZYNQ:Hello World 实验-PS-串口打印“Hello World”
  • 【微服务】初识
  • 有效的字母异位词【字符串哈希】
  • ARM base instruction -- movk
  • [M滑动窗口] lc3305、lc3306. 元音辅音字符串计数 I、II(恰好型滑动窗口+双指针+思维+代码实现)
  • https://www.aitoolpath.com/ 一个工具数据库,目前储存了有2000+各种工具。每日更新
  • Leetcode.5 最长回文子串 (快手面试题)
  • ECS - 多端口任务
  • 人工智能辅助的神经康复
  • 技术人生-电脑突然卡顿怎么办
  • 初识CyberBattleSim