Skip to content

Commit eaa3f96

Browse files
2286 - Booking Concert Tickets in Groups.md
1 parent 04ff72f commit eaa3f96

File tree

1 file changed

+234
-0
lines changed

1 file changed

+234
-0
lines changed
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
---
2+
id: Booking-concert-tickets-in-groups
3+
title: Booking Concert Tickets in Groups
4+
sidebar_label: 2286 Booking Concert Tickets in Groups
5+
tags:
6+
- Java
7+
- Binary Search
8+
- Design
9+
- Segmnent Tree
10+
- Binary Indexed Tree
11+
description: "This document provides a solution where we need to design a ticketing system that can allocate seats."
12+
---
13+
14+
## Problem
15+
16+
A concert hall has $n$ rows numbered from $0$ to $n - 1$, each with $m$ seats, numbered from $0$ to $m - 1$. You need to design a ticketing system that can allocate seats in the following cases:
17+
18+
- If a group of $k$ spectators can sit **together** in a row.
19+
20+
- If **every** member of a group of $k$ spectators can get a seat. They may or **may not** sit together.
21+
22+
Note that the spectators are very picky. Hence:
23+
24+
- They will book seats only if each member of their group can get a seat with row number **less than or equal** to $maxRow$. $maxRow$ can vary from group to group.
25+
26+
- In case there are multiple rows to choose from, the row with the **smallest** number is chosen. If there are multiple seats to choose in the same row, the seat with the **smallest** number is chosen.
27+
28+
Implement the $BookMyShow$ class:
29+
30+
- $BookMyShow(int n, int m)$ Initializes the object with $n$ as number of rows and $m$ as number of seats per row.
31+
32+
- $int[] gather(int k, int maxRow)$ Returns an array of length $2$ denoting the row and seat number (respectively) of the **first seat** being allocated to the $k$ members of the group, who must sit **together**. In other words, it returns the smallest possible $r$ and $c$ such that all $[c, c + k - 1]$ seats are valid and empty in row $r$, and $r <= maxRow$. Returns $[]$ in case it is **not possible** to allocate seats to the group.
33+
34+
- $boolean scatter(int k, int maxRow)$ Returns $true$ if all $k$ members of the group can be allocated seats in rows $0$ to $maxRow$, who may or **may not** sit together. If the seats can be allocated, it allocates $k$ seats to the group with the **smallest** row numbers, and the smallest possible seat numbers in each row. Otherwise, returns $false$.
35+
36+
### Examples
37+
38+
**Example 1:**
39+
40+
```
41+
Input: ["BookMyShow", "gather", "gather", "scatter", "scatter"]
42+
[[2, 5], [4, 0], [2, 0], [5, 1], [5, 1]]
43+
44+
Output: [null, [0, 0], [], true, false]
45+
46+
Explanation:
47+
48+
BookMyShow bms = new BookMyShow(2, 5); // There are 2 rows with 5 seats each
49+
bms.gather(4, 0); // return [0, 0]
50+
// The group books seats [0, 3] of row 0.
51+
52+
bms.gather(2, 0); // return []
53+
// There is only 1 seat left in row 0,
54+
// so it is not possible to book 2 consecutive seats.
55+
56+
bms.scatter(5, 1); // return True
57+
// The group books seat 4 of row 0 and seats [0, 3] of row 1.
58+
59+
bms.scatter(5, 1); // return False
60+
// There is only one seat left in the hall.
61+
```
62+
63+
### Constraints
64+
65+
- $1 <= n <= 5 * 10^4$
66+
- $1 <= m, k <= 10^9$
67+
- $0 <= maxRow <= n - 1$
68+
- At most $5 * 10^4$ calls in total will be made to $gather$ and $scatter$.
69+
---
70+
71+
## Approach
72+
73+
To solve the problem, we need to understand the nature of the allowed moves:
74+
75+
1. **Segment Tree**:
76+
77+
- **Build**: Construct the segment tree with initial values, where each node stores the sum and maximum number of seats in the range it represents.
78+
79+
- **Update**: Update the segment tree when seats are booked, modifying the relevant nodes to reflect the new seat counts.
80+
81+
- **Queries**:
82+
83+
- **Gather Query**: Find a row with at least **'k'** seats available within the first **'maxRow'** rows.
84+
85+
- **Sum Query**: Compute the total number of seats available within the first **'maxRow'** rows.
86+
87+
2. **BookMyShow Class**:
88+
89+
- **Constructor**: Initialize the segment tree and an array to keep track of seats available in each row.
90+
91+
- **Gather**: Check if there is a row with at least **'k'** seats and update the tree and row seat count accordingly.
92+
93+
- **Scatter**: Allocate **'k'**
94+
95+
## Solution for Booking Concert Tickets in Groups
96+
97+
- The problem revolves around efficiently managing and querying seat allocations in a theater. The segment tree is used to handle range queries and updates swiftly, ensuring that operations like finding available seats or updating seat counts are performed in logarithmic time.
98+
99+
#### Code in Java
100+
101+
```java
102+
class BookMyShow {
103+
static class SegTree{
104+
long sum[]; // store sum of seats in a range
105+
long segTree[]; // store maximum seats in a range
106+
int m, n;
107+
public SegTree(int n, int m) {
108+
this.m = m;
109+
this.n = n;
110+
segTree = new long[4*n];
111+
sum = new long[4*n];
112+
build(0, 0, n-1, m);
113+
}
114+
115+
private void build(int index, int lo, int hi, long val){
116+
if(lo == hi){
117+
segTree[index] = val; // initialize segement tree with initial seat capacity
118+
sum[index] = val; // initialize "sum" with initial seat capacity of a row
119+
return;
120+
}
121+
int mid = (lo + hi)/2;
122+
build(2*index +1, lo, mid, val); // build left sub tree
123+
build(2*index +2, mid+1, hi, val); // build right sub tree
124+
segTree[index] = Math.max(segTree[2*index + 1], segTree[2*index + 2]); // maximum seats in a row for subtrees
125+
sum[index] = sum[2*index + 1] + sum[2*index + 2]; // sum of seats in a range
126+
}
127+
128+
private void update(int index, int lo, int hi, int pos, int val){
129+
/**
130+
Method to update segment tree based on the available seats in a row
131+
**/
132+
if(lo == hi){
133+
segTree[index] = val;
134+
sum[index] = val;
135+
return;
136+
}
137+
int mid = (lo + hi) / 2;
138+
if (pos <= mid) { // position to update is in left
139+
update(2 * index + 1, lo, mid, pos, val);
140+
} else { // position to update is in right
141+
update(2 * index + 2, mid+1, hi, pos, val);
142+
}
143+
// update segment tree and "sum" based on the update in "pos" index
144+
segTree[index] = Math.max(segTree[2*index + 1] , segTree[2*index + 2]);
145+
sum[index] = sum[2*index + 1] + sum[2*index + 2];
146+
}
147+
148+
public void update(int pos, int val){
149+
update(0, 0, n - 1 , pos, val);
150+
}
151+
152+
public int gatherQuery(int k, int maxRow){
153+
return gatherQuery(0, 0, n - 1 , k, maxRow);
154+
}
155+
156+
private int gatherQuery(int index, int lo, int hi, int k, int maxRow){
157+
/**
158+
Method to check if seats are available in a single row
159+
**/
160+
if(segTree[index] < k || lo > maxRow)
161+
return -1;
162+
if(lo == hi) return lo;
163+
int mid = (lo + hi) / 2;
164+
int c = gatherQuery(2*index + 1, lo, mid, k, maxRow);
165+
if(c == -1){
166+
c = gatherQuery(2*index + 2, mid +1, hi, k, maxRow);
167+
}
168+
return c;
169+
}
170+
171+
public long sumQuery(int k, int maxRow){
172+
return sumQuery(0, 0, n-1, k, maxRow);
173+
}
174+
175+
private long sumQuery(int index, int lo, int hi, int l, int r){
176+
if(lo > r || hi < l ) return 0; // not in range
177+
if(lo >= l && hi <= r) return sum[index]; // in range
178+
int mid = (lo + hi)/2;
179+
return sumQuery(2*index+1, lo, mid, l, r) + sumQuery(2*index+2, mid+1, hi, l, r);
180+
}
181+
}
182+
183+
SegTree segTree;
184+
int[] rowSeats; // stores avaiable seats in a row, helps to find the vacant seat in a row
185+
186+
public BookMyShow(int n, int m) {
187+
segTree = new SegTree(n, m);
188+
rowSeats = new int[n];
189+
Arrays.fill(rowSeats, m); // initialize vacant seats count to "m" for all the rows
190+
}
191+
192+
193+
public int[] gather(int k, int maxRow) {
194+
int row = segTree.gatherQuery(k, maxRow); // find row which has k seats
195+
if(row == -1) return new int[]{}; // can't find a row with k seats
196+
int col = segTree.m - rowSeats[row]; // find column in the row which has k seats
197+
rowSeats[row] -= k; // reduce the seats
198+
segTree.update(row, rowSeats[row]); // update the segment tree
199+
return new int[]{row, col};
200+
201+
}
202+
203+
public boolean scatter(int k, int maxRow) {
204+
long sum = segTree.sumQuery(0, maxRow); // find the sum for the given range [0, maxRow]
205+
if(sum < k) return false; // can't find k seats in [0, maxRow]
206+
207+
for(int i=0; i<=maxRow && k !=0 ; i++){
208+
if(rowSeats[i] > 0){ // if current row has seats then allocate those seats
209+
long t = Math.min(rowSeats[i], k);
210+
rowSeats[i] -= t;
211+
k -= t;
212+
segTree.update(i,rowSeats[i]); // update the segment tree
213+
}
214+
}
215+
return true;
216+
}
217+
}
218+
```
219+
220+
### Complexity Analysis
221+
222+
#### Time Complexity: $O(logn)$
223+
224+
> **Reason**: Segment tree operations are build: $O(n)$, update: $O(log n)$, gather query: $O(log n)$, sum query: $O(log n)$; BookMyShow operations are constructor: $O(n)$, gather: $O(log n)$, scatter: $O(n log n)$.
225+
226+
#### Space Complexity: $O(n)$
227+
228+
> **Reason**: The space complexity is $O(n)$, The **'rowSeats'** array requires O(n) space to store the seat counts for each row.
229+
230+
# References
231+
232+
- **LeetCode Problem:** [Booking Concert Tickets in Groups](https://leetcode.com/problems/booking-concert-tickets-in-groups/description/)
233+
- **Solution Link:** [Booking Concert Tickets in Groups Solution on LeetCode](https://leetcode.com/problems/booking-concert-tickets-in-groups/solutions/)
234+
- **Authors LeetCode Profile:** [Vivek Vardhan](https://leetcode.com/u/vivekvardhan43862/)

0 commit comments

Comments
 (0)