June 2024, Week 4: June 17th - June 23rd
June 17 -> 633. Sum of Square Numbers
Given a non-negative integer c
, decide whether there are two integers a
and b
such that a^2 + b^2 = c
.
Example 1:
Input: c = 5
Output: true
Explanation: 1 * 1 + 2 * 2 = 5
Example 2:
Input: c = 3
Output: false
Constraints:
0 <= c <= 2^31 - 1
Approach 1: Two-Pointer Technique
Understanding the Core Idea
The core idea of this solution is to find if the given integer c
can be decomposed into the sum of two perfect squares using a two-pointer approach. Here's the breakdown of the concept:
Two-Pointer Approach:
The function initializes two pointers:
start_index
at 0 andend_index
at the square root ofc
. These pointers represent potential values of 'a' and 'b'.In each iteration, it calculates the
squares_sum
of the squares of these pointers.If
squares_sum
equalsc
, it means we've found a pair of integers (a, b) whose squares add up toc
.If
squares_sum
is less thanc
, we incrementstart_index
to increase the sum (since a^2 is the smaller term).If
squares_sum
is greater thanc
, we decrementend_index
to decrease the sum (since b^2 is the larger term).
Mathematical Basis:
The algorithm is based on the fact that if a number
c
can be expressed as the sum of two squares, the numbersa
andb
must each be less than or equal to the square root ofc
. This ensures we only check relevant values.
Code Walkthrough
Initialization:
start_index
is set to 0, representing the smallest possible square.end_index
is set to the integer part of the square root ofc
, representing the largest possible square within the range.
Main Loop (Two-Pointer Search):
The
while
loop runs as long asstart_index
is less than or equal toend_index
.In each iteration:
squares_sum
is calculated asstart_index * start_index + end_index * end_index
.Decision Point (Conditional Statements):
If
squares_sum == c
, the function returnsTrue
(pair found).If
squares_sum < c
, we increasestart_index
by 1.If
squares_sum > c
, we decreaseend_index
by 1.
Result Calculation/Return:
If the loop completes without finding a match, the function returns
False
(no pair exists).
Complexity Analysis
Time Complexity:
where is the input integer. In the worst case, the while
loop will run up to the square root oftimes.
Space Complexity:
(Constant): The algorithm uses only a fixed number of variables ( start_index
,end_index
,squares_sum
), and this number doesn't grow with the input size.
Example
Input: c = 98
Step-by-Step Walkthrough:
Initialization:
start_index
is set to 0.end_index
is set to the integer part of the square root of 98, which is 9.
Main Loop (Two-Pointer Search):
While
(Iteration 1): squares_sum
=Since 81 < 98, we increment
start_index
to 1.
While
(Iteration 2): squares_sum
=Since 82 < 98, we increment
start_index
to 2.
While
(Iteration 3): squares_sum
=Since 85 < 98, we increment
start_index
to 3.
While
(Iteration 4): squares_sum
=Since 90 < 98, we increment
start_index
to 4.
While
(Iteration 5): squares_sum
=Since 97 < 98, we increment
start_index
to 5.
While
(Iteration 6): squares_sum
=Since 106 > 98, we decrement
end_index
to 8.
While
(Iteration 7): squares_sum
=Since 89 < 98, we increment
start_index
to 6.
While
(Iteration 8): squares_sum
=Since 100 > 98, we decrement
end_index
to 7.
While
(Iteration 9): squares_sum
=Since 85 < 98, we increment
start_index
to 7.
While
(Iteration 10): squares_sum
=Since 98 == 98, we have found a valid pair (7, 7), and the function returns
True
.
Loop Termination: The loop terminates when
squares_sum == c
, indicating a valid pair of integers has been found.Iteration Summary:
start_index
end_index
squares_sum
Comparison
Action
0
9
81
81 < 98
start_index += 1
1
9
82
82 < 98
start_index += 1
2
9
85
85 < 98
start_index += 1
3
9
90
90 < 98
start_index += 1
4
9
97
97 < 98
start_index += 1
5
9
106
106 > 98
end_index -= 1
5
8
89
89 < 98
start_index += 1
6
8
100
100 > 98
end_index -= 1
6
7
85
85 < 98
start_index += 1
7
7
98
98 == 98
Return True
Result Calculation/Final Steps:
The function directly returns
True
as soon as it finds the valid pair (7, 7). It does not need to calculate or return any additional values.The pair (7, 7) satisfies the condition
, confirming that 98 can be expressed as the sum of two squares.
Approach 2: Number Theory (Fermat's Theorem)
Understanding the Core Idea
The core idea of this solution is to leverage Fermat's Theorem on sums of two squares to determine if a given number can be expressed as such. Fermat's theorem states:
In simpler terms, a number can be expressed as the sum of two squares unless it has a prime factor of the form
This is because a prime of the form
Another important concept is the Brahmagupta-Fibonacci identity, which states that the product of two sums of two squares is itself a sum of two squares. This property allows us to combine the squares of two numbers to form a new sum of squares:
This identity is crucial in the context of Fermat's theorem and the decomposition of numbers into sums of squares. When a prime factor
Prime Factorization: The solution systematically checks for prime factors of
up to its square root. Counting Divisibility: For each prime factor, it counts how many times it divides
evenly (tracked by divisors_count
).Checking Fermat's Condition: If a prime factor of the form
has an odd divisors_count
, the number cannot be a sum of squares (returnsFalse
).Base Case: After iterating through smaller primes, the remaining value of
is either 1 or a prime. It checks if this remaining prime is of the form . If it is, it returns False
; otherwise, it returnsTrue
.
Code Walkthrough
Initialization:
index
is initialized to 2, the smallest prime number.
Main Loop (Checking Prime Factors):
The
while
loop iterates as long as the square ofindex
(potential prime factor) is less than or equal toc
.Inner Loop (Counting Divisors):
If
c
is divisible byindex
, a nestedwhile
loop repeatedly dividesc
byindex
to count its occurrences.
Decision Points (Fermat's Condition):
After the inner loop, it checks if
divisors_count
is odd (indicating an odd power) and ifindex
is of the form4k + 3
. If both are true, the function returnsFalse
.
Base Case (After Main Loop):
If the main loop completes without returning,
c
is either 1 or a prime.It checks if the remaining
c
is of the form4k + 3
. If so, it returnsFalse
; otherwise,True
.
Complexity Analysis
Time Complexity:
. The main loop runs up to times. For each iteration, the inner loop might run up to times in the worst case (for a prime that divides c
many times).
Space Complexity:
(Constant): The algorithm uses a fixed number of variables ( index
,divisors_count
,c
), regardless of the input size.
Example
Input: c = 98
Step-by-Step Walkthrough:
Initialization:
index
is initialized to 2, the smallest prime number.
Main Loop (Checking Prime Factors):
While
(Iteration 1): index = 2
c
is divisible byindex
(98 % 2 == 0).Inner loop counts the divisors:
divisors_count = 1
,c = 49
(after division)divisors_count
is 1 andindex
(2) is not of the form 4k+3, so the loop continues.index
is incremented to 3.
While
(Iteration 2): index = 3
c
is not divisible byindex
(49 % 3 != 0), so the loop continues.index
is incremented to 4.
While
(Iteration 3): index = 4
c
is not divisible byindex
(49 % 4 != 0), so the loop continues.index
is incremented to 5.
While
(Iteration 4): index = 5
c
is not divisible byindex
(49 % 5 != 0), so the loop continues.index
is incremented to 6.
While
(Iteration 5): index = 6
c
is not divisible byindex
(49 % 6 != 0), so the loop continues.index
is incremented to 7.
While
(Iteration 6): index = 7
c
is divisible byindex
(49 % 7 == 0).Inner loop counts the divisors:
divisors_count = 1
,c = 7
divisors_count = 2
,c = 1
index
(7) is of the form 4k+3, but sincedivisors_count
is even (2), the loop continues.index
is incremented to 8.
Loop Termination: The loop terminates after iteration 6 because
index * index
(64) is not less than or equal to the current value ofc
(1).Iteration Summary/Visual Aids:
c
index
divisors_count
index % 4 == 3
Result
108
2
1
False
Continue
49
3
0
False
Continue
49
4
0
False
Continue
49
5
0
False
Continue
49
6
0
False
Continue
49
7
2
True
Continue (Even exponent)
Result Calculation/Final Steps:
After the loop,
c
is 1. Since 1 is not of the form 4k + 3, the function returnsTrue
, indicating that 98 can be expressed as the sum of two squares.
Visualizing the Pairing of Squares:
Since the factorization of 98 is
, the prime factor 7 (of the form ) appears with an even exponent (2), allowing it to be paired off and expressed as a sum of squares. This can be visualized using the Brahmagupta-Fibonacci identity to combine the squares of 7 into a new sum of squares:
We know that
, and we can express as . With the factorization, we get the product of these two sums of squares: .
Using the identity, we can combine these to get
.
June 18 -> 826. Most Profit Assigning Work
You have n
jobs and m
workers. You are given three arrays: difficulty
, profit
, and worker
where:
difficulty[i]
andprofit[i]
are the difficulty and the profit of theith
job, andworker[j]
is the ability ofjth
worker (i.e., thejth
worker can only complete a job with difficulty at mostworker[j]
).
Every worker can be assigned at most one job, but one job can be completed multiple times.
For example, if three workers attempt the same job that pays 1 dollar, then the total profit will be 3 dollars. If a worker cannot complete any job, their profit is
$0
.
Return the maximum profit we can achieve after assigning the workers to the jobs.
Example 1:
Input: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7]
Output: 100
Explanation:
Workers are assigned jobs of difficulty [4,4,6,6], and they get a profit of [20,20,30,30] separately.
Example 2:
Input: difficulty = [85,47,57], profit = [24,66,99], worker = [40,25,25]
Output: 0
Constraints:
n == difficulty.length
n == profit.length
m == worker.length
1 <= n, m <= 10^4
1 <= difficulty[i], profit[i], worker[i] <= 10^5
Approach 1: Memoization Name
Understanding the Core Idea
The core idea of this solution is to leverage a precomputed list of maximum profits achievable for each difficulty level up to the maximum ability of the workers. This allows a quick lookup of the best possible profit for any worker's ability, ensuring efficient assignment of workers to jobs.
Precomputation of Maximum Profits: The solution first builds a list to store the maximum-profit achievable for each difficulty level up to the maximum worker ability.
Accumulation of Profits: It ensures that for any difficulty level, the profit reflects the highest possible profit up to that level. This way, a worker can always find the best job they can perform.
Efficient Assignment: By using the precomputed list, the solution quickly sums up the maximum possible profit for each worker based on their ability.
Code Walkthrough
Initialization:
max_ability = max(worker)
: Finds the maximum ability among all workers. This is the highest difficulty level we need to consider.max_profit_per_diff = [0] * (max_ability + 1)
: Creates a list to store the maximum-profit achievable for each difficulty level from 0 tomax_ability
. It's initialized with zeros.
Build Maximum Profit per Difficulty:
for diff, prof in zip(difficulty, profit)
: Iterates through each job's difficulty (diff
) and profit (prof
).if diff <= max_ability
: Checks if the current job's difficulty is within the range of worker abilities we need to consider.max_profit_per_diff[diff] = max(max_profit_per_diff[diff], prof)
: Updates the maximum profit for the current job's difficulty level if the current job offers a higher profit.
Accumulate Maximum Profit:
for index in range(1, max_ability + 1)
: Iterates through each difficulty level from 1 tomax_ability
.max_profit_per_diff[index] = max(max_profit_per_diff[index], max_profit_per_diff[index - 1])
: Updates the maximum profit for the current difficulty level to be the maximum of either its current value or the maximum profit of the previous difficulty level. This ensures that even if a job has a lower difficulty, it can still be chosen if it offers a higher profit.
Result Calculation/Return:
sum(max_profit_per_diff[ability] for ability in worker)
: Iterates through each worker's ability and sums up their maximum achievable profits based on the precomputedmax_profit_per_diff
list.
Complexity Analysis
Time Complexity:
, where: is the length of difficulty
andprofit
(number of jobs)is the length of worker
(number of workers)is the maximum value in worker
This is because the algorithm iterates over difficulty
and profit
once worker
once
Space Complexity:
This is because the algorithm uses a list max_profit_per_diff
to store maximum profits per difficulty level up to the maximum ability. The size of this list is directly proportional to max_ability
.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
The function starts by finding the maximum ability of the workers:
max_ability = max(worker)
, which is12
.An array
max_profit_per_diff
of sizemax_ability + 1
is initialized to store the maximum profit for each difficulty level up tomax_ability
:max_profit_per_diff = [0] * (max_ability + 1)
.
Main Loop (Building Max Profit Array):
Iteration 1:
Current Job: (difficulty = 5, profit = 10)
Since
5 <= 12
, updatemax_profit_per_diff[5]
:0 -> 10
.
Iteration 2:
Current Job: (difficulty = 12, profit = 30)
Since
12 <= 12
, updatemax_profit_per_diff[12]
:0 -> 30
.
Iteration 3:
Current Job: (difficulty = 2, profit = 20)
Since
2 <= 12
, updatemax_profit_per_diff[2]
:0 -> 20
.
Iteration 4:
Current Job: (difficulty = 6, profit = 25)
Since
6 <= 12
, updatemax_profit_per_diff[6]
:0 -> 25
.
Iteration 5:
Current Job: (difficulty = 15, profit = 50)
Since
15 > 12
, skip this job.
Iteration 6:
Current Job: (difficulty = 7, profit = 35)
Since
7 <= 12
, updatemax_profit_per_diff[7]
:0 -> 35
.
Iteration 7:
Current Job: (difficulty = 9, profit = 40)
Since
9 <= 12
, updatemax_profit_per_diff[9]
:0 -> 40
.
Iteration Summary:
max_profit_per_diff: [0, 0, 20, 0, 0, 10, 25, 35, 0, 40, 0, 0, 30]Second Loop (Propagating Maximum Profits):
Iteration 1/12:
Here we update the maximum profit for each difficulty level based on the previous level's maximum profit.
Update
max_profit_per_diff[1]
:0 -> 0
.
Iteration 2/12:
Since the previous maximum profit is
0
, the maximum profit for2
remains20
.Update
max_profit_per_diff[2]
:20 -> 20
.
Iteration 3/12:
Since the previous maximum profit is
20
and this level's profit is0
, the maximum profit for3
gets updated to20
.Update
max_profit_per_diff[3]
:0 -> 20
.
Iteration 4/12 - 12/12:
The loop continues, updating the maximum profit for each difficulty level based on the previous level's maximum profit.
The final updated
max_profit_per_diff
array is:max_profit_per_diff: [0, 0, 20, 20, 20, 20, 25, 35, 35, 40, 40, 40, 40]
Result Calculation/Final Steps:
Worker 1:
Ability: 10
Maximum Profit: 40
Current Total Profit:
0 + 40 = 40
Worker 2:
Ability: 5
Maximum Profit: 20
Current Total Profit:
40 + 20 = 60
Worker 3:
Ability: 7
Maximum Profit: 35
Current Total Profit:
60 + 35 = 95
Worker 4:
Ability: 12
Maximum Profit: 40
Current Total Profit:
95 + 40 = 135
Worker 5:
Ability: 8
Maximum Profit: 35
Current Total Profit:
135 + 35 = 170
The function returns the total maximum profit of
170
.
Approach 2: Binary Search
Understanding the Core Idea
The central concept of this solution is to leverage sorting and binary search to efficiently match workers to the most profitable jobs they can perform. The solution transforms the job list to reflect the highest profit available up to each difficulty level, enabling quick lookups.
Sorting Jobs by Difficulty: The jobs are sorted by difficulty to facilitate binary search and cumulative-profit calculations.
Cumulative-Profit Calculation: A transformation is applied to the sorted jobs to ensure each job entry reflects the highest profit up to that difficulty level.
Binary Search for Worker Assignment: For each worker, a binary search is used to quickly find the highest-paying job they can perform.
Code Walkthrough
Initialization:
jobs = sorted(zip(difficulty, profit))
: Creates a list of tuples where each tuple contains the difficulty and profit of a job. It then sorts this list in ascending order based on the difficulty.
Job Transformation:
max_profit_so_far = 0
: Initializes a variable to keep track of the maximum profit seen so far.for index, job in enumerate(jobs)
: Iterates over the sorted jobs.max_profit_so_far = max(max_profit_so_far, job[1])
: Updatesmax_profit_so_far
if the current job has a higher profit.jobs[index] = (job[0], max_profit_so_far)
: Replaces the profit in the current job tuple withmax_profit_so_far
. This transformation ensures that for each job, the profit stored in the tuple represents the maximum profit achievable up to that job's difficulty level.
Profit Calculation:
total_profit = 0
: Initializes the total profit earned by all workers.for ability in worker
: Iterates over the abilities of each worker.index = bisect_right(jobs, (ability, float('inf')))
: Performs a binary search to find the rightmost index in thejobs
list where the tuple (ability, infinity) would be inserted while maintaining the sorted order. This essentially finds the index of the first job with a difficulty greater than the worker's ability.if index > 0
: Checks if the worker is qualified for at least one job.total_profit += jobs[index - 1][1]
: If the worker is qualified, add the profit of the highest-paying job they can do (located atindex - 1
) to the total profit.
Result Calculation/Return:
Returns the calculated
total_profit
.
Complexity Analysis
Time Complexity:
, where: is the number of jobs is the number of workers
This is because the algorithm:
Sorts the jobs:
Transforms the job list:
Performs binary search for each worker:
Space Complexity:
This is because the algorithm uses additional space for the jobs
list which has the same length as the input lists difficulty
and profit
.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
The
jobs
list is created by pairing correspondingdifficulty
andprofit
values and then sorting them in ascending order based on difficulty:[(2, 20), (5, 10), (6, 25), (7, 35), (9, 40), (12, 30), (15, 50)]
.A variable
max_profit_so_far
is initialized to 0. It will track the highest profit encountered as the jobs are processed.
Main Loop (Transforming Jobs with Max Profit):
The loop iterates through each job in the sorted
jobs
list.Iteration 1:
Job: (2, 20)
max_profit_so_far
is updated to 20 (max of 0 and 20).The job in
jobs
is replaced with (2, 20).
Iteration 2:
Job: (5, 10)
max_profit_so_far
remains 20.The job in
jobs
is replaced with (5, 20).
Iterations 3-7: Similar logic is applied to the remaining jobs.
max_profit_so_far
gets updated as needed, ensuring that the profit associated with each job represents the maximum profit achievable up to that difficulty level.
Iteration Summary (Transformed Jobs):
The provided table illustrates how the
jobs
list is transformed during the main loop. The "Max Profit So Far" column shows how this value is tracked and used to update the profit component of each job.
Iteration
Original Job
Max Profit So Far
Updated Job
1
(2, 20)
20
(2, 20)
2
(5, 10)
20
(5, 20)
3
(6, 25)
25
(6, 25)
4
(7, 35)
35
(7, 35)
5
(9, 40)
40
(9, 40)
6
(12, 30)
40
(12, 40)
7
(15, 50)
50
(15, 50)
Calculating Total Profit (Worker Loop):
The loop iterates through the
worker
list.Iteration 1 (Worker with ability 10):
Binary search (
bisect_right
) is used to find the rightmost job injobs
with a difficulty less than or equal to the worker's ability (10). This leads to index 5.Since the index is greater than 0, the profit of the job at index 4 is added to
total_profit
(40).
Iteration 2 (Worker with ability 5):
Binary search finds index 2.
The profit of the job at index 1 (20) is added to
total_profit
. The total profit is now 60.
Iteration 3 (Worker with ability 7):
Binary search finds index 4.
The profit of the job at index 3 (35) is added to
total_profit
. The total profit is now 95.
**Iteration 4
Binary search finds index 6.
The profit of the job at index 5 (40) is added to
total_profit
. The total profit is now 135.
**Iteration 5
Binary search finds index 4.
The profit of the job at index 3 (35) is added to
total_profit
. The total profit is now 170.
Final Result:
The function returns the calculated
total_profit
, which is 170 in this example. This represents the maximum achievable profit by assigning the workers to the available jobs.
Approach 3: Two-Pointer Technique
Understanding the Core Idea
The core idea of this solution is to use sorting and a two-pointer technique to efficiently assign the most profitable jobs to workers based on their abilities. The solution processes jobs and workers in a sorted order, ensuring that each worker is matched with the best possible job they can perform.
Sorting Jobs and Workers: Both the jobs and workers are sorted to facilitate efficient traversal and profit calculation.
Two-Pointer Technique: The solution uses a two-pointer technique to iterate through the sorted job list and keep track of the maximum profit available up to the current worker's ability. This technique ensures that the solution only processes each job and worker once, contributing to its efficiency.
Accumulating Profits: By maintaining a running maximum of job profits, the solution ensures that each worker is assigned the best possible job they can perform, maximizing total profit.
Code Walkthrough
Initialization:
jobs = sorted(zip(difficulty, profit))
: Creates a list of tuples where each tuple contains the difficulty and profit of a job. It then sorts this list in ascending order based on the difficulty.total_profit = 0
: Initializes the total profit earned by all workers.max_profit_so_far = 0
: Initializes a variable to keep track of the maximum profit seen so far for any job within the current worker's ability.index = 0
: Initializes an index to keep track of the current job being considered.
Iterative Profit Calculation:
for ability in sorted(worker)
: Iterates over the abilities of each worker in ascending order.while index < len(jobs) and jobs[index][0] <= ability
: This loop continues as long as there are jobs left to consider, and the current job's difficulty is less than or equal to the worker's ability.max_profit_so_far = max(max_profit_so_far, jobs[index][1])
: Updatesmax_profit_so_far
if the current job has a higher profit than any previously seen job within the worker's ability range.index += 1
: Moves on to the next job.
total_profit += max_profit_so_far
: Adds the maximum profit achievable by the current worker to thetotal_profit
.
Result Calculation/Return:
Returns the calculated
total_profit
.
Complexity Analysis
Time Complexity:
, where: is the number of jobs is the number of workers
This is because the algorithm:
Sorts the jobs:
Sorts the workers:
Iterates over jobs and workers: While the nested loops might seem like
, note that the index
for jobs only increases and never goes back. So, in total, we iterate over each job and each worker only once, resulting in.
Since the sorting operations dominate, the overall time complexity is
Space Complexity:
This is because the algorithm uses additional space for the jobs
list which has the same length as the input lists difficulty
and profit
(
Example
Input:
Step-by-Step Walkthrough:
Initialization:
The code combines
difficulty
andprofit
into pairs and sorts them by difficulty:jobs = [(2, 20), (5, 10), (6, 25), (7, 35), (9, 40), (12, 30), (15, 50)]
.The
worker
array is also sorted:[5, 7, 8, 10, 12]
.total_profit
is initialized to 0.max_profit_so_far
(to track the highest profit seen so far) andindex
(to track the current position injobs
) are both set to 0.
Main Loop (Calculate Total Profit):
The loop iterates over the sorted
worker
array:worker = [5, 7, 8, 10, 12]
.Iteration 1 (Worker with ability 5):
Current max_profit_so_far: 0
The
while
loop finds the jobs that the worker can do (difficulty <= 5).Job (2, 20) is within the worker's ability. Update
max_profit_so_far
to 20.Job (5, 10) is within the worker's ability. Keep
max_profit_so_far
at 20.Job (6, 25) is not within the worker's ability (difficulty > 5). Exit the loop.
The worker's profit (20) is added to
total_profit
, making it 20.
Iteration 2 (Worker with ability 7):
Current max_profit_so_far: 20
The
while
loop finds the jobs that the worker can do (up to difficulty 7).Job (6, 25) is within the worker's ability. Update
max_profit_so_far
to 25.Job (7, 35) is within the worker's ability. Update
max_profit_so_far
to 35.Job (9, 40) is not within the worker's ability (difficulty > 7). Exit the loop
The worker's profit (35) is added to
total_profit
, making it 55 (20 + 35).
Iteration 3 (Worker with ability 8):
Current max_profit_so_far: 35
The
while
loop finds the jobs that the worker can do (up to difficulty 8).Since the worker's ability is 8 and the next job's difficulty is 9, the loop doesn't execute.
The worker's profit (35) is added to
total_profit
, making it 90 (55 + 35).
Iteration 4 (Worker with ability 10):
Current max_profit_so_far: 35
The
while
loop finds the jobs that the worker can do (up to difficulty 10).Job (9, 40) is within the worker's ability. Update
max_profit_so_far
to 40.Job (12, 30) is not within the worker's ability (difficulty > 10). Exit the loop.
The worker's profit (40) is added to
total_profit
, making it 130 (90 + 40).
Iteration 5 (Worker with ability 12):
Current max_profit_so_far: 40
The
while
loop finds the jobs that the worker can do (up to difficulty 12).Job (12, 30) is within the worker's ability. Keep
max_profit_so_far
at 40.Job (15, 50) is not within the worker's ability (difficulty > 12). Exit the loop.
The worker's profit (40) is added to
total_profit
, making it 170 (130 + 40).
Iteration Summary:
The table demonstrates how
max_profit_so_far
andtotal_profit
change with each iteration of the loop.
Iteration
Worker Ability
Max Profit So Far
Total Profit
1
5
20
20
2
7
35
55
3
8
35
90
4
10
40
130
5
12
40
170
Result Calculation/Final Steps:
After the loop completes, the final value of
total_profit
(170) is returned, representing the maximum-profit achievable.
June 19 -> 1482. Minimum Number of Days to Make m Bouquets
You are given an integer array bloom_day
, an integer m
and an integer k
.
You want to make m
bouquets. To make a bouquet, you need to use k
adjacent flowers from the garden.
The garden consists of n
flowers, the ith
flower will bloom in the bloom_day[i]
and then can be used in exactly one bouquet.
Return the minimum number of days you need to wait to be able to make m
bouquets from the garden. If it is impossible to make m bouquets return -1
.
Example 1:
Input: bloom_day = [1,10,3,10,2], m = 3, k = 1
Output: 3
Explanation:
Let us see what happened in the first three days. x means flower bloomed and _ means flower did not bloom in the garden.
We need three bouquets each should contain one flower.
After day 1: [x, _, _, _, _] // we can only make one bouquet.
After day 2: [x, _, _, _, x] // we can only make two bouquets.
After day 3: [x, _, x, _, x] // we can make three bouquets. The answer is 3.
Example 2:
Input: bloom_day = [1,10,3,10,2], m = 3, k = 2
Output:-1
Explanation:
We need three bouquets each has two flowers, that means we need six flowers. We only have five flowers, so it is impossible to get the needed bouquets, and we return -1.
Example 3:
Input: bloom_day = [7,7,7,7,12,7,7], m = 2, k = 3
Output: 12
Explanation:
We need two bouquets each should have three flowers.
Here is the garden after the 7 and 12 days:
After day 7: [x, x, x, x, _, x, x]
We can make one bouquet of the first three flowers that bloomed. We cannot make another bouquet from the last three flowers that bloomed because they are not adjacent.
After day 12: [x, x, x, x, x, x, x]
It is clear that we can make two bouquets in different ways.
Constraints:
bloom_day.length == n
1 <= n <= 10^5
1 <= bloom_day[i] <= 10^9
1 <= m <= 10^6
1 <= k <= n
Approach 1.1: Binary Search
Understanding the Core Idea
The solution leverages binary search to efficiently find the minimum number of days required to make m
bouquets. It exploits the monotonic property of the problem: if it's possible to make m
bouquets after waiting x
days, it's also possible after waiting x + 1
days.
Binary Search on Days: The search space is the range of possible days (from the minimum to the maximum bloom day). The solution repeatedly checks the midpoint of this range.
Bouquet Formation Check: For each candidate day, the code simulates bouquet formation using adjacent flowers that have bloomed by that day.
Search Space Reduction: If enough bouquets can be made, the search space is narrowed to earlier days. Otherwise, it's narrowed to later days.
Code Walkthrough
Base Case Check: The code first checks if it's even possible to make
m
bouquets withk
adjacent flowers each, given the total number of flowers. If not, it returns -1.can_make_bouquets(day)
Function:This function simulates the garden on a given
day
.It iterates through the bloom days of each flower.
If a flower has bloomed by the given
day
, it's added to a potential bouquet (flowers
counter incremented).Once
k
adjacent flowers are found, a bouquet is formed (bouquet_count
incremented).If
m
or more bouquets are formed, the function immediately returnsTrue
.If a flower hasn't bloomed, the current potential bouquet is reset (
flowers
set to 0).Finally, the function returns whether
m
or more bouquets were formed.
Binary Search Initialization:
left_index
starts at the earliest bloom day (minimum ofbloom_day
).right_index
starts at the latest bloom day (maximum ofbloom_day
).
Binary Search Loop:
The loop continues as long as there is a range of days to explore (
left_index < right_index
).mid_index
is calculated as the middle of the current range.The
can_make_bouquets
function checks ifm
bouquets can be formed bymid_index
day.If yes, the answer might be found earlier (or at
mid_index
), soright_index
is set tomid_index
.If no, the answer must be later, so
left_index
is set tomid_index + 1
.
Result:
When the loop ends,
left_index
holds the minimum day whenm
bouquets can be formed. This value is returned as the final result.
Complexity Analysis
Time Complexity:
, where n
is the length ofbloom_day
andD
is the difference between the maximum and minimum bloom days.The binary search takes
time to find the minimum number of days. In each iteration, the
can_make_bouquets
function takestime to simulate the garden.
Space Complexity:
, the solution uses a constant amount of extra space, regardless of the input size. This is because only a few variables are used to track the indices and counters.
Example
Input: bloom_day = [3, 2, 4, 9, 10, 4, 3, 4]
, m = 3
, k = 2
Step-by-Step Walkthrough:
Initialization:
The function first checks if it's possible to make three bouquets of size 2, given 8 flowers. Since 3 * 2 = 6 and 6 <= 8, it's possible, and the function proceeds.
The binary search range is initialized:
left_index = 2
(the minimum value inbloom_day
)right_index = 10
(the maximum value inbloom_day
)
Main Loop (Binary Search):
Iteration 1:
mid_index = (2 + 10) // 2 = 6
can_make_bouquets(6)
is called:The function simulates forming bouquets with flowers that bloom by day 6.
It finds only two bouquets can be made. (See iteration summary table below)
Flower
Bloom Day
Bloom Day <= 6
Action
Flowers
Bouquets (2 size)
1
3
Yes
Increment Flowers
1
0
2
2
Yes
Make Bouquet and Reset Flowers
2
1
3
4
Yes
Increment Flowers
1
1
4
9
No
Reset Flowers
0
1
5
10
No
Reset Flowers
0
1
6
4
Yes
Increment Flowers
1
1
7
3
Yes
Make Bouquet and Reset Flowers
2
2
8
4
Yes
Increment Flowers
1
2
Since this is less than
m = 3
, it returnsFalse
.
The binary search range is updated:
left_index = 7
(since we need to look at later bloom days)
Iteration 2:
mid_index = (7 + 10) // 2 = 8
can_make_bouquets(8)
is called:The function simulates forming bouquets with flowers that bloom by day 8.
It again finds only two bouquets can be made. (See the iteration summary table below)
Flower
Bloom Day
Bloom Day <= 8
Action
Flowers
Bouquets (2 size)
1
3
Yes
Increment Flowers
1
0
2
2
Yes
Make Bouquet and Reset Flowers
2
1
3
4
Yes
Increment Flowers
1
1
4
9
No
Reset Flowers
0
1
5
10
No
Reset Flowers
0
1
6
4
Yes
Increment Flowers
1
1
7
3
Yes
Make Bouquet and Reset Flowers
2
2
8
4
Yes
Increment Flowers
1
2
Since this is less than
m = 3
, it returnsFalse
.
The binary search range is updated:
left_index = 9
Iteration 3:
mid_index = (9 + 10) // 2 = 9
can_make_bouquets(9)
is called:The function simulates forming bouquets with flowers that bloom by day 9.
This time, it successfully makes three bouquets. (See the iteration summary table below)
Flower
Bloom Day
Bloom Day <= 9
Action
Flowers
Bouquets (2 size)
1
3
Yes
Increment Flowers
1
0
2
2
Yes
Make Bouquet and Reset Flowers
2
1
3
4
Yes
Increment Flowers
1
1
4
9
Yes
Make Bouquet and Reset Flowers
2
2
5
10
No
Reset Flowers
0
2
6
4
Yes
Increment Flowers
1
2
7
3
Yes
Make Bouquet and Reset Flowers
2
3
It returns
True
.
The binary search range is updated:
right_index = 9
Loop Termination:
The loop terminates because
left_index
andright_index
both become 9.
Binary Search Iteration Summary:
Iteration
Left Index
Right Index
Mid Index
Can Make Bouquets?
Action
1
2
10
6
No
left = mid + 1 (7)
2
7
10
8
No
left = mid + 1 (9)
3
9
10
9
Yes
right = mid (9)
Result Calculation/Final Steps:
The final value of
left_index
is 9, indicating that you need to wait 9 days to make three bouquets.The function returns 9 as the result.
Approach 1.2: Binary Search on Sorted Set
Understanding the Core Idea
This solution builds upon the core idea of binary search like the previous one, but with an optimization focused on the search space. Instead of searching within the full range of bloom days (which could be large), it leverages the fact that only the unique bloom days matter.
Binary Search on Unique Bloom Days: The search space is reduced to the sorted set of unique bloom days. This potentially drastically reduces the number of iterations in the binary search.
Bouquet Formation Check: The
can_make_bouquets
function remains largely the same, but it now implicitly handles the gaps between bloom days by counting how many bouquets can be formed from the consecutive bloomed flowers.Optimized Search: The binary search operates on the indices of the sorted unique bloom days, making the comparisons more efficient.
Code Walkthrough
Base Case Check: Identical to the previous solution, this checks if making
m
bouquets is even possible.can_make_bouquets(day)
Function:The function's logic is slightly modified from the previous version.
Instead of resetting
flowers
to 0 whenever a bloom day is exceeded, it now adds the currentflowers
count ( divided byk
) tobouquet_count
. This efficiently accounts for all bouquets formed up to the current point.The rest of the logic remains the same: check if enough bouquets are made and return the result.
Unique Bloom Days Preparation:
unique_bloom_days
is created by:Converting the
bloom_day
list to a set to get unique days.Sorting the set to have a defined order for binary search.
Binary Search Initialization and Loop:
left_index
andright_index
are initialized for the indices ofunique_bloom_days
.The loop and its logic remain almost the same as before, but now it operates on the indices of
unique_bloom_days
.
Result:
After the loop,
unique_bloom_days[left_index]
gives the minimum bloom day required.
Complexity Analysis
Time Complexity:
, where n
is the length ofbloom_day
. This is an improvement over the previousin cases where there are many repeated bloom days. Creating the set takes
time, and sorting it takes , where u
is the number of unique bloom days.The binary search now takes
iterations. Each iteration of
can_make_bouquets
still takestime. In total, we have
.
Since
Space Complexity:
in the worst case, to store the set of unique bloom days. This is potentially much better than the previous if there are many repeated values. If u
is small compared ton
, it can be considered.
Example
Input: bloom_day = [3, 2, 4, 9, 10, 4, 3, 4]
, m = 3
, k = 2
Step-by-Step Walkthrough:
Initialization:
The function first checks if it's possible to make three bouquets of size 2, given 8 flowers. Since
and , it's possible, and the function proceeds. The unique bloom days are extracted and sorted:
unique_bloom_days = [2, 3, 4, 9, 10]
The binary search range is initialized to the indices of
unique_bloom_days
:left_index = 0
(the first index)right_index = 4
(the last index)
Main Loop (Binary Search):
Iteration 1:
mid_index = (0 + 4) // 2 = 2
can_make_bouquets(unique_bloom_days[2])
, which iscan_make_bouquets(4)
, is called:The function simulates forming bouquets with flowers that bloom by day 4.
It finds that only two bouquets can be made. (See iteration summary table below)
Flower
Bloom Day
Bloom Day <= 4
Action
Flowers
Bouquets (2 size)
1
3
Yes
Increment Flowers
1
0
2
2
Yes
Increment Flowers
2
0
3
4
Yes
Increment Flowers
3
0
4
9
No
Reset Flowers/Calculate Bouquets
0
1
5
10
No
Reset Flowers/Calculate Bouquets
0
1
6
4
Yes
Increment Flowers
1
1
7
3
Yes
Increment Flowers
2
1
8
4
Yes
Final Bouquet Calculation
3
2
Since this is less than
m = 3
, it returnsFalse
.
The binary search range is updated:
left_index = 3
(since we need to look at later bloom days)
Iteration 2:
mid_index = (3 + 4) // 2 = 3
can_make_bouquets(unique_bloom_days[3])
, which iscan_make_bouquets(9)
, is called:The function simulates forming bouquets with flowers that bloom by day 9.
This time, it successfully makes three bouquets. (See iteration summary table below)
Flower
Bloom Day
Bloom Day <= 9
Action
Flowers
Bouquets (2 size)
1
3
Yes
Increment Flowers
1
0
2
2
Yes
Increment Flowers
2
0
3
4
Yes
Increment Flowers
3
0
4
9
Yes
Increment Flowers
4
0
5
10
No
Reset Flowers/Calculate Bouquets
0
2
6
4
Yes
Increment Flowers
1
2
7
3
Yes
Increment Flowers
2
2
8
4
Yes
Final Bouquet Calculation
3
3
It returns
True
.
The binary search range is updated:
right_index = 3
Loop Termination:
The loop terminates because
left_index
andright_index
both become 3.
Binary Search Iteration Summary:
Iteration
Left Index
Right Index
Mid Index
Can Make Bouquets?
Action
1
0
4
2
No
left = mid + 1 (3)
2
3
4
3
Yes
right = mid (3)
Result Calculation/Final Steps:
The final value of
left_index
is 3.The function returns
unique_bloom_days[3]
, which is9
, indicating that you need to wait 9 days to make three bouquets.
June 20 -> 1552. Magnetic Force Between Two Balls
In the universe Earth C-137, Rick discovered a special form of magnetic force between two balls if they are put in his new invented basket. Rick has n
empty baskets, the ith
basket is at position[i]
, Morty has m
balls and needs to distribute the balls into the baskets such that the minimum magnetic force between any two balls is maximum.
Rick stated that magnetic force between two different balls at positions x
and y
is |x - y|
.
Given the integer array position
and the integer m
. Return the required force.
Example 1:

Input: position = [1,2,3,4,7], m = 3
Output: 3
Explanation: Distributing the three balls into baskets 1, 4 and 7 will make the magnetic force between ball pairs [3, 3, 6]. The minimum magnetic force is 3. We cannot achieve a larger minimum magnetic force than 3.
Example 2:
Input: position = [5,4,3,2,1,1000000000], m = 2
Output: 999999999
Explanation: We can use baskets 1 and 1000000000.
Constraints:
n == position.length
2 <= n <= 10^5
1 <= position[i] <= 10^9
All integers in
position
are distinct.2 <= m <= position.length
Approach 1: Binary Search
Understanding the Core Idea
The central concept of this solution is to leverage binary search to efficiently find the maximum possible minimum distance between any two balls. This approach works because the problem has a monotonic property: if we can place m
balls with a minimum distance d
, we can also place them with any distance smaller than d
.
Binary Search on Answer: Instead of checking all possible distances, we use binary search to narrow down the range of potential answers quickly.
Greedy Ball Placement: For each potential minimum distance, we use a greedy approach to place balls as far apart as possible.
Monotonicity: The ability to place balls at a given minimum distance implies we can place them at any smaller distance, allowing for binary search.
Code Walkthrough
Helper Function (
can_place_balls
):Initializes
remaining_balls
tom - 1
, representing the number of balls left to place after the first.Sets
next_valid_position
to the first position plus themin_distance
.Iterates through the remaining positions:
If the current position (
pos
) is greater than or equal tonext_valid_position
, a ball is placed,remaining_balls
is decremented, andnext_valid_position
is updated.If all balls are placed (
remaining_balls
becomes 0), it returnsTrue
.
Returns
False
if not all balls could be placed,True
otherwise.
Initialization:
Sorts the
position
array in ascending order.Initializes the search space with
start_index = 1
(minimum possible force) andend_index = (position[-1] - position[0]) // (m - 1)
(maximum possible average distance rounded down).
Main Loop (Binary Search):
While
start_index < end_index
:Calculates the
mid_index
with a slight bias towards the right to ensure progress.Calls
can_place_balls
withmid_index
as the minimum distance.If
can_place_balls
returnsTrue
:Updates
start_index
tomid_index
, as a larger minimum distance might be possible.
Otherwise:
Updates
end_index
tomid_index - 1
, as the minimum distance must be smaller.
Result Calculation/Return:
After the loop ends,
start_index
will have converged to the maximum possible minimum distance, which is returned.
Complexity Analysis
Time Complexity:
, where is the number of positions and range is . This comes from two main operations:
Sorting the positions:
Binary search with ball placement check:
iterations, each doing an check.
Combined, this gives
Space Complexity:
, where is the number of positions. This is due to the space required for sorting the
position
array, as Python's sort() method uses TimSort, which can require additional space in the worst case.The rest of the algorithm uses only a constant amount of extra space.
Example
Input: position = [64, 16, 128, 8, 2, 32, 1, 4], m = 4
Step-by-Step Walkthrough:
Initialization:
The
position
list is sorted:[1, 2, 4, 8, 16, 32, 64, 128]
start_index
is set to 1 (minimum possible distance)end_index
is set to (128 - 1) // (4 - 1) = 42 (maximum possible average distance)
Binary Search Loop:
While 1 < 42 (Iteration 1):
mid_index = 1 + (1 + 42) // 2 = 22
can_place_balls(22)
returns TrueBalls are placed at positions 1, 32, 64, 128
start_index
is updated to 22
While 22 < 42 (Iteration 2):
mid_index = 1 + (22 + 42) // 2 = 33
can_place_balls(33)
returns FalseOnly 3 balls can be placed (at 1, 64, 128)
end_index
is updated to 32
Iteration 3:
mid_index = 1 + (22 + 32) // 2 = 28
can_place_balls(28)
returns TrueBalls are placed at positions 1, 32, 64, 128
start_index
is updated to 28
Iteration 4:
mid_index = 1 + (28 + 32) // 2 = 31
can_place_balls(31)
returns TrueBalls are placed at positions 1, 32, 64, 128
start_index
is updated to 31
Iteration 5:
mid_index = 1 + (31 + 32) // 2 = 32
can_place_balls(32)
returns FalseOnly 3 balls can be placed (at 1, 64, 128)
end_index
is updated to 31
Loop Termination:
The loop terminates when
start_index
(31) is no longer less thanend_index
(31)
Visual Aid: Iteration Summary Table
Iteration
Start Index
End Index
Mid Index
Can Place
1
1
42
22
True
2
22
42
33
False
3
22
32
28
True
4
28
32
31
True
5
31
32
32
False
Result Calculation/Final Steps:
The algorithm returns
start_index
, which is 31This means the maximum possible minimum distance between any two balls is 31
The final result indicates that we can place four balls in the baskets such that the minimum distance between any two balls is 31, and this is the maximum possible minimum distance we can achieve. We can place them at positions 1, 32, 64, and 128. The distance between each position is 31, 32, and 64, respectively; hence, the minimum distance is 31.
June 21 -> 1052. Grumpy Bookstore Owner
There is a bookstore owner that has a store open for n
minutes. Every minute, some number of customers enters the store. You are given an integer array customers
of length n
where customers[i]
is the number of the customer that enters the store at the start of the ith
minute and all those customers leave after the end of that minute.
In some minutes, the bookstore owner is grumpy. You are given a binary array grumpy where grumpy[i]
is 1
if the bookstore owner is grumpy during the ith
minute, and is 0
otherwise.
When the bookstore owner is grumpy, the customers of that minute are not satisfied, otherwise, they are satisfied.
The bookstore owner knows a secret technique to keep themselves not grumpy for minutes
consecutive minutes, but can only use it once.
Return the maximum number of customers that can be satisfied throughout the day.
Example 1:
Input: customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], minutes = 3
Output: 16
Explanation: The bookstore owner keeps themselves not grumpy for the last 3 minutes. The maximum number of customers that can be satisfied = 1 + 1 + 1 + 1 + 7 + 5 = 16.
Example 2:
Input: customers = [1], grumpy = [0], minutes = 1
Output: 1
Constraints:
n == customers.length == grumpy.length
1 <= minutes <= n <= 2 * 10^4
0 <= customers[i] <= 1000
grumpy[i]
is either0
or1
.
Approach 1: Sliding Window
Understanding the Core Idea
The central concept of this solution is to leverage a sliding window technique to maximize customer satisfaction given the constraint of a limited period where the bookstore owner can suppress their grumpiness. The solution exploits the pattern in the data by separating normally satisfied customers from potentially satisfied customers during the owner's non-grumpy period.
Two-part Satisfaction Calculation: The solution divides customer satisfaction into two parts: those naturally satisfied when the owner isn't grumpy, and additional customers that could be satisfied during the "non-grumpy" window.
Sliding Window for Optimization: A sliding window of size
minutes
is used to find the optimal period for the owner to use their "non-grumpy" technique, maximizing additional customer satisfaction.Single-pass Approach: The solution cleverly combines the calculation of normally satisfied customers and the sliding window technique into a single pass through the data, optimizing for efficiency.
Code Walkthrough
Initialization:
satisfied_customers = 0 potential_customers = 0These variables track normally satisfied customers and potential additional satisfied customers in the current window.
Initial Window Calculation:
for customer, grump in zip(customers[:minutes], grumpy[:minutes]): if grump: potential_customers += customer else: satisfied_customers += customerThis loop calculates initial satisfaction for the first
minutes
window, separating normally satisfied from potential additional customers.Maximum Potential Tracking:
max_potential_customers = potential_customersInitializes the maximum potential additional satisfied customers with the first window's value.
Sliding Window Implementation:
for minute in range(minutes, len(customers)):This loop slides the window through the remaining data, one customer at a time.
Window Update:
if grumpy[minute]: potential_customers += customers[minute] else: satisfied_customers += customers[minute]Updates satisfaction counts for the new customer entering the window.
Window Tail Removal:
if grumpy[minute - minutes]: potential_customers -= customers[minute - minutes]Removes the contribution of the customer leaving the window if they were part of the potential satisfaction count.
Maximum Update:
max_potential_customers = max(max_potential_customers, potential_customers)Updates the maximum potential additional satisfied customers if the current window is better.
Result Calculation/Return:
return satisfied_customers + max_potential_customersCombines normally satisfied customers with the maximum additional satisfied customers from the optimal "non-grumpy" window.
Complexity Analysis
Time Complexity:
), where is the number of minutes (length of the customers list). This is because the algorithm makes a single pass through the data, performing constant-time operations at each step.
Space Complexity:
, as the algorithm uses a fixed amount of additional space (a few variables) regardless of the input size. It doesn't create any data structures that scale with the input.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
satisfied_customers = 0
potential_customers = 0
Main Loop (Initial Window Calculation):
Since
minutes = 3
, the initial window covers the first three minutes:Iteration 1 (minute 0):
customer = 1
,grump = 0
Owner is not grumpy, so add to
satisfied_customers
satisfied_customers = 1
,potential_customers = 0
Iteration 2 (minute 1):
customer = 0
,grump = 1
Owner is grumpy, but no customers to add to
potential_customers
satisfied_customers = 1
,potential_customers = 0
Iteration 3 (minute 2):
customer = 1
,grump = 0
Owner is not grumpy, so add to
satisfied_customers
satisfied_customers = 2
,potential_customers = 0
Initial Window Summary:
[1, 0, 1, 2, 1, 1, 7, 5] Customers [0, 1, 0, 1, 0, 1, 0, 1] Grumpy [S P S] Window S: Satisfied = 2, P: Potential = 0, Max Potential = 0
Sliding Window Loop:
Iteration 4 (minute 3):
customer = 2
,grump = 1
Owner is grumpy, add customers to
potential_customers
potential_customers = 0 + 2 = 2
Current window: [1, 3]
Update
max_potential_customers = 2
[1, 0, 1, 2, 1, 1, 7, 5] Customers [0, 1, 0, 1, 0, 1, 0, 1] Grumpy [P S P] Window S: Satisfied = 2, P: Potential = 2, Max Potential = 2
Iteration 5 (minute 4):
customer = 1
,grump = 0
Owner is not grumpy, add customer to
satisfied_customers
satisfied_customers = 2 + 1 = 3
Current window: [2, 4]
No change to
potential_customers
[1, 0, 1, 2, 1, 1, 7, 5] Customers [0, 1, 0, 1, 0, 1, 0, 1] Grumpy [S P S] Window S: Satisfied = 3, P: Potential = 2, Max Potential = 2
Iteration 6 (minute 5):
customer = 1
,grump = 1
Owner is grumpy, add customers to
potential_customers
potential_customers = 2 + 1 = 3
Current window: [3, 5]
Update
max_potential_customers = 3
[1, 0, 1, 2, 1, 1, 7, 5] Customers [0, 1, 0, 1, 0, 1, 0, 1] Grumpy [P S P] Window S: Satisfied = 3, P: Potential = 3, Max Potential = 3
Iteration 7 (minute 6):
customer = 7
,grump = 0
Owner is not grumpy, add to
satisfied_customers
satisfied_customers = 10
Current window: [4, 6]
Remove 2 from
potential_customers
(from minute 3)potential_customers = 3 - 2 = 1
The maximum potential customers remain at 3
[1, 0, 1, 2, 1, 1, 7, 5] Customers [0, 1, 0, 1, 0, 1, 0, 1] Grumpy [S P S] Window S: Satisfied = 10, P: Potential = 1, Max Potential = 3
Iteration 8 (minute 7):
customer = 5
,grump = 1
Owner is grumpy, add customers to
potential_customers
potential_customers = 5 + 1 = 6
Current window: [5, 7]
Update
max_potential_customers = 6
[1, 0, 1, 2, 1, 1, 7, 5] Customers [0, 1, 0, 1, 0, 1, 0, 1] Grumpy [P S P] Window S: Satisfied = 10, P: Potential = 6, Max Potential = 6
Visual Aid:
Minute
Window
Customers
Grumpy
Satisfied Customers
Potential Customers
Max Potential
0
-
1
0
1
0
0
1
-
0
1
1
0
0
2
[0, 2]
1
0
2
0
0
3
[1, 3]
2
1
2
2
2
4
[2, 4]
1
0
3
2
2
5
[3, 5]
1
1
3
3
3
6
[4, 6]
7
0
10
1
3
7
[5, 7]
5
1
10
6
6
Result Calculation:
Final
satisfied_customers = 10
Final
max_potential_customers = 6
Total satisfied customers =
satisfied_customers + max_potential_customers = 10 + 6 = 16
The algorithm returns 16 as the maximum number of customers that can be satisfied throughout the day.
June 22 -> 1248. Count Number of Nice Subarrays
Given an array of integers nums
and an integer k
. A continuous subarray is called nice if there are k
odd numbers on it.
Return the number of nice subarrays.
Example 1:
Input: nums = [1,1,2,1,1], k = 3
Output: 2
Explanation: The only subarrays with three odd numbers are [1,1,2,1] and [1,2,1,1].
Example 2:
Input: nums = [2,4,6], k = 1
Output: 0
Explanation: There are no odd numbers in the array.
Example 3:
Input: nums = [2,2,2,1,2,2,1,2,2,2], k = 2
Output: 16
Constraints:
1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length
Approach 1: Sliding Window and Counting
Understanding the Core Idea
The central concept of this solution is to use a sliding window technique combined with a counting approach to efficiently find nice subarrays. The solution exploits the fact that once a nice subarray is found, any extension of it that doesn't include new odd numbers is also nice.
Sliding Window: The solution maintains a window that expands when odd numbers are encountered and contracts when the odd count exceeds
k
.Incremental Counting: Instead of recounting for each subarray, it incrementally updates the count of nice subarrays.
Code Walkthrough
Initialization:
total_nice_subarrays = 0 current_nice_subarrays = 0 odd_count = 0 start_index = 0The function initializes several variables:
total_nice_subarrays
to store the final count of nice subarrays.current_nice_subarrays
to track the number of valid subarrays ending at the current position.odd_count
to count the number of odd numbers in the current window.start_index
to mark the beginning of the current window.
Iterate Through Array:
for num in nums:This loop processes each number in the input array.
Handle Odd Numbers:
if num % 2 == 1: odd_count += 1 current_nice_subarrays = 0When an odd number is encountered, the odd count is incremented and the current nice subarray count is reset.
Window Adjustment and Counting:
while odd_count == k: current_nice_subarrays += 1 odd_count -= nums[start_index] % 2 start_index += 1When
k
odd numbers are found, this loop counts nice subarrays by moving the start of the window. It increments the count for each valid start position and stops when an odd number is removed from the window.Accumulate Nice Subarray Count:
total_nice_subarrays += current_nice_subarraysThe count of nice subarrays ending at the current position is added to the total.
Return Result:
return total_nice_subarraysThe function returns the total count of nice subarrays found.
Complexity Analysis
Time Complexity:
, where is the length of the input array nums. This is because each element in the array is processed at most twice: once in the outer for loop and potentially once in the inner while loop.
Space Complexity:
, as the algorithm uses only a constant amount of extra space regardless of the input size. It maintains a few variables ( total_nice_subarrays
,current_nice_subarrays
,odd_count
,start_index
) that do not grow with the input size.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
total_nice_subarrays = 0
: Keeps track of all nice subarrays foundcurrent_nice_subarrays = 0
: Counts nice subarrays ending at the current positionodd_count = 0
: Tracks the number of odd integers in the current windowstart_index = 0
: Marks the start of the current window
Main Loop (Iterating through nums):
Iteration 1 (num = 2):
2 is even, so no changes to
odd_count
orcurrent_nice_subarrays
No nice subarrays found yet
Iteration 2 (num = 1):
1 is odd, so
odd_count
increases to 1current_nice_subarrays
resets to 0 (new odd number encountered)Still no nice subarrays (need two odd numbers)
Iteration 3 (num = 2):
2 is even, no changes to counters
No nice subarrays yet
Iteration 4 (num = 1):
1 is odd,
odd_count
increases to 2current_nice_subarrays
resets to 0odd_count == k
, so we enter the while loop:current_nice_subarrays
increases to 1Check if nums[0] (2) is odd - it's not, so
odd_count
remains 2start_index
increases to 1Still
odd_count == k
, so loop continuescurrent_nice_subarrays
increases to 2nums[1] (1) is odd, so
odd_count
decreases to 1start_index
increases to 2
total_nice_subarrays
becomes 2
Iteration 5 (num = 2):
2 is even, no changes to
odd_count
total_nice_subarrays
increases to 4 (2 + 2)
Iteration 6 (num = 1):
1 is odd,
odd_count
increases to 2current_nice_subarrays
resets to 0odd_count == k
, enter while loop:current_nice_subarrays
increases to 1nums[2] (2) is not odd,
odd_count
stays 2start_index
increases to 3Still
odd_count == k
, continue loopcurrent_nice_subarrays
increases to 2nums[3] (1) is odd,
odd_count
decreases to 1start_index
increases to 4
total_nice_subarrays
becomes 6 (4 + 2)
Iteration 7 (num = 2):
2 is even, no changes to
odd_count
total_nice_subarrays
increases to 8 (6 + 2)
Iteration 8 (num = 2):
2 is even, no changes to
odd_count
total_nice_subarrays
increases to 10 (8 + 2)
Loop Termination:
The loop ends after processing all elements in
nums
Final state:
total_nice_subarrays = 10
,odd_count = 1
,start_index = 4
Result Calculation:
The final result is the value of
total_nice_subarrays
, which is 10This represents the total number of subarrays containing exactly
k = 2
odd numbers
Approach 2: Two-Pass and Counting
Understanding the Core Idea
The central concept of this solution is to leverage a two-pass approach to efficiently count nice subarrays. It exploits the structure of the array by focusing on the distribution of odd numbers and the even numbers between them.
Even Number Counting: The solution counts the number of even integers between each pair of odd integers, including the ends of the array.
Combinatorial Calculation: It uses these counts to calculate the total number of nice subarrays without explicitly listing them.
Code Walkthrough
Initialization:
even_counts = [] current_even_count, odd_count = 1, 0even_counts
will store the count of even numbers between odd numbers, andcurrent_even_count
is initialized to 1 to account for the start of the array.Count Even Numbers and Identify Odd Numbers:
for num in nums: if num % 2 == 0: current_even_count += 1 else: even_counts.append(current_even_count) current_even_count = 1 even_counts.append(current_even_count)This loop counts even numbers between odd numbers. When an odd number is encountered, the current count of even numbers is appended to
even_counts
, and the count is reset. The finaleven_counts.append(current_even_count)
accounts for even numbers at the end of the array.Calculate Nice Subarrays:
total_nice_subarrays = 0 for left_even_count, right_even_count in zip(even_counts, even_counts[k:]): total_nice_subarrays += left_even_count * right_even_countThis loop calculates the number of nice subarrays. It pairs the count of even numbers before a sequence of
k
odd numbers with the count after, multiplying them to get the number of nice subarrays for that sequence.Return Result:
return total_nice_subarraysThe function returns the total count of nice subarrays found.
Complexity Analysis
Time Complexity:
, where n is the length of the input array nums. This is because the algorithm makes two passes through the data: one to count even numbers between odd numbers, and another to calculate the number of nice subarrays.
Space Complexity:
, as the algorithm uses only a constant amount of extra space regardless of the input size. It maintains a few variables ( even_counts
,current_even_count
,odd_count
) that do not grow with the input size.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
even_counts = []
: List to store counts of consecutive even numberscurrent_even_count = 1
: Initialize count of the current sequence of even numbers
First Pass: Counting Even Numbers
Iteration 1 (num = 2):
2 is even, so
current_even_count
increases to 2even_counts
remains empty: []
Iteration 2 (num = 1):
1 is odd, so we append
current_even_count
(2) toeven_counts
Reset
current_even_count
to 1even_counts
becomes [2]
Iteration 3 (num = 2):
2 is even, so
current_even_count
increases to 2even_counts
remains [2]
Iteration 4 (num = 1):
1 is odd, so we append
current_even_count
(2) toeven_counts
Reset
current_even_count
to 1even_counts
becomes [2, 2]
Iteration 5 (num = 2):
2 is even, so
current_even_count
increases to 2even_counts
remains [2, 2]
Iteration 6 (num = 1):
1 is odd, so we append
current_even_count
(2) toeven_counts
Reset
current_even_count
to 1even_counts
becomes [2, 2, 2]
Iteration 7 (num = 2):
2 is even, so
current_even_count
increases to 2even_counts
remains [2, 2, 2]
Iteration 8 (num = 2):
2 is even, so
current_even_count
increases to 3even_counts
remains [2, 2, 2]
Loop Termination:
After processing all numbers, append final
current_even_count
(3) toeven_counts
Final state of
even_counts
: [2, 2, 2, 3]
Second Pass: Calculating Nice Subarrays
Iteration 1:
left_even_count = 2
(fromeven_counts[0]
)right_even_count = 2
(fromeven_counts[2]
)Calculate nice subarrays: 2 * 2 = 4
total_nice_subarrays
becomes 4
Iteration 2:
left_even_count = 2
(fromeven_counts[1]
)right_even_count = 3
(fromeven_counts[3]
)Calculate nice subarrays: 2 * 3 = 6
total_nice_subarrays
increases to 10 (4 + 6)
Visual Aid:
Iteration Summary Table:
Subarray
Left Even Count
Right Even Count
Nice Subarrays
Total Nice Subarrays
1
2
2
4
4
2
2
3
6
10
Result Calculation/Final Steps:
The final result is the value of
total_nice_subarrays
, which is 10This represents the total number of subarrays containing exactly two odd numbers
June 23 -> 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit
Given an array of integers nums
and an integer limit
, return the size of the longest non-empty subarray such that the absolute difference between any two elements of this subarray is less than or equal to limit
.
Example 1:
Input: nums = [8,2,4,7], limit = 4
Output: 2
Explanation: All subarrays are:
[8] with maximum absolute diff |8-8| = 0 <= 4.
[8,2] with maximum absolute diff |8-2| = 6 > 4.
[8,2,4] with maximum absolute diff |8-2| = 6 > 4.
[8,2,4,7] with maximum absolute diff |8-2| = 6 > 4.
[2] with maximum absolute diff |2-2| = 0 <= 4.
[2,4] with maximum absolute diff |2-4| = 2 <= 4.
[2,4,7] with maximum absolute diff |2-7| = 5 > 4.
[4] with maximum absolute diff |4-4| = 0 <= 4.
[4,7] with maximum absolute diff |4-7| = 3 <= 4.
[7] with maximum absolute diff |7-7| = 0 <= 4.
Therefore, the size of the longest subarray is 2.
Example 2:
Input: nums = [10,1,2,4,7,2], limit = 5
Output: 4
Explanation: The subarray [2,4,7,2] is the longest since the maximum absolute diff is |2-7| = 5 <= 5.
Example 3:
Input: nums = [4,2,2,2,4,4,2,2], limit = 0
Output: 3
Constraints:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
0 <= limit <= 10^9
Approach 1: Sliding Window with Sorted List
Understanding the Core Idea
The central concept of this solution is to leverage a sliding window approach combined with a sorted list to efficiently find the longest subarray that satisfies the given condition. This technique allows us to maintain a dynamic view of the current subarray while keeping track of its minimum and maximum elements.
Sliding Window: The solution uses two pointers (
left_index
and the current iteration index) to define a window that expands and contracts as we iterate through the array.Sorted List: A sorted list is maintained to represent the elements in the current window, allowing for quick access to the minimum and maximum elements.
Dynamic Window Adjustment: As new elements are added, the window expands. If the condition is violated, the window contracts from the left side.
Code Walkthrough
Initialization:
left_index = 0 sorted_nums = []The
left_index
variable keeps track of the left boundary of our sliding window.sorted_nums
is an empty list that will store the elements of the current window in sorted order.Iterating Through the Array:
for num in nums:This loop processes each element of the input array
nums
sequentially.Inserting New Element:
bisect.insort(sorted_nums, num)The current element
num
is inserted intosorted_nums
at its correct position, maintaining the sorted order.bisect.insort
is used for efficient insertion in a sorted list.Checking and Adjusting Window:
if sorted_nums[-1] - sorted_nums[0] > limit: sorted_nums.pop(bisect.bisect(sorted_nums, nums[left_index]) - 1) left_index += 1This block checks if the difference between the maximum (last element) and minimum (first element) of the sorted list exceeds the limit. If so, it removes the leftmost element of the window from
sorted_nums
and moves the left boundary of the window.Result Calculation/Return:
return len(nums) - left_indexThe function returns the length of the longest valid subarray, which is the total length of the array minus the left index of the sliding window.
Complexity Analysis
Time Complexity:
, where is the length of the input array nums
. This is because for each element in the array, we perform an insertion into a sorted list using bisect.insort
(in the worst case). However, in practice, it can be much faster if the subarrays tend to be short.
Space Complexity:
, where is the length of the input array nums
. This is because in the worst case, thesorted_nums
list might contain all elements of the input array.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
Set
left_index = 0
Initialize empty
sorted_nums
list
Main Loop (Iterate through
nums
):Iteration 1 (
nums[0] = 10
):Insert 10 into
sorted_nums
:sorted_nums = [10]
No window adjustment needed (10 - 10 = 0 <= 5)
Current subarray length: 1
Iteration 2 (
nums[1] = 1
):Insert 1 into
sorted_nums
:sorted_nums = [1, 10]
Window adjustment: 10 - 1 = 9 > 5
Remove 10 from
sorted_nums
:sorted_nums = [1]
Update
left_index
to 1
Current subarray length: 1
Iteration 3 (
nums[2] = 2
):Insert 2 into
sorted_nums
:sorted_nums = [1, 2]
No window adjustment needed (2 - 1 = 1 <= 5)
Current subarray length: 2
Iteration 4 (
nums[3] = 4
):Insert 4 into
sorted_nums
:sorted_nums = [1, 2, 4]
No window adjustment needed (4 - 1 = 3 <= 5)
Current subarray length: 3
Iteration 5 (
nums[4] = 7
):Insert 7 into
sorted_nums
:sorted_nums = [1, 2, 4, 7]
Window adjustment: 7 - 1 = 6 > 5
Remove 1 from
sorted_nums
:sorted_nums = [2, 4, 7]
Update
left_index
to 2
Current subarray length: 3
Iteration 6 (
nums[5] = 2
):Insert 2 into
sorted_nums
:sorted_nums = [2, 2, 4, 7]
No window adjustment needed (7 - 2 = 5 <= 5)
Current subarray length: 4
Loop Termination:
The loop ends after processing all elements in
nums
Final state:
left_index = 2
Visual Aid: Iteration Summary Table
Iteration
Current Number
Left Index
Sorted Nums
Current Length
1
10
0
[10]
1
2
1
1
[1]
1
3
2
1
[1, 2]
2
4
4
1
[1, 2, 4]
3
5
7
2
[2, 4, 7]
3
6
2
2
[2, 2, 4, 7]
4
Result Calculation/Final Steps:
The algorithm calculates the result as
len(nums) - left_index
Result = 6 - 2 = 4
The longest subarray where the absolute difference between any two elements is at most 5 has a length of 4, which corresponds to the subarray [2, 4, 7, 2].
Approach 2: Sliding Window with Heaps
Understanding the Core Idea
The central concept of this solution is to leverage a sliding window approach combined with two heaps (min-heap and max-heap) to efficiently find the longest subarray that satisfies the given condition. This technique allows us to maintain a dynamic view of the current subarray while keeping track of its minimum and maximum elements in a more efficient manner.
Sliding Window: The solution uses two pointers (
left_index
andright_index
) to define a window that expands and contracts as we iterate through the array.Dual Heap Structure: Two heaps (min-heap and max-heap) are used to efficiently track the minimum and maximum elements in the current window.
Dynamic Window Adjustment: As new elements are added, the window expands. If the condition is violated, the window contracts from the left side until the condition is satisfied again.
Code Walkthrough
Initialization:
max_heap = [] min_heap = [] left_index = 0 max_length = 0Two empty heaps are initialized:
max_heap
for maximum elements andmin_heap
for minimum elements.left_index
tracks the left boundary of the sliding window, andmax_length
stores the length of the longest valid subarray found so far.Iterating Through the Array:
for right_index, num in enumerate(nums):This loop processes each element of the input array
nums
sequentially, usingright_index
as the current position.Adding Elements to Heaps:
heapq.heappush(max_heap, (-num, right_index)) heapq.heappush(min_heap, (num, right_index))The current element
num
is added to both heaps. Note that formax_heap
, we use the negative ofnum
to create a max-heap using Python's min-heap implementation.Adjusting Window:
while -max_heap[0][0] - min_heap[0][0] > limit: left_index = min(max_heap[0][1], min_heap[0][1]) + 1 while max_heap[0][1] < left_index: heapq.heappop(max_heap) while min_heap[0][1] < left_index: heapq.heappop(min_heap)This block checks if the difference between the maximum and minimum elements exceeds the limit. If so, it moves the left boundary of the window and removes elements from the heaps that are now outside the window.
Updating Maximum Length:
max_length = max(max_length, right_index - left_index + 1)After each iteration, update the
max_length
if the current window is longer than the previous maximum.Result Calculation/Return:
return max_lengthThe function returns the length of the longest valid subarray.
Complexity Analysis
Time Complexity:
, where is the length of the input array nums
. This is because for each element in the array, we perform heap operations (push and pop) which take time. In the worst case, we might need to perform these operations for each element.
Space Complexity:
, where is the length of the input array nums
. This is because in the worst case, all elements might be stored in the heaps simultaneously.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
Initialize empty
max_heap
andmin_heap
Set
left_index = 0
andmax_length = 0
Main Loop (Iterate through nums):
Iteration 1 (nums[0] = 10):
Push (10, 0) to
max_heap
as (-10, 0) and tomin_heap
as (10, 0)The heaps become:
max_heap = [(-10, 0)]
min_heap = [(10, 0)]
No window adjustment needed (10 - 10 = 0 <= 5)
Update
max_length
to 1
Iteration 2 (nums[1] = 1):
Push (1, 1) to both heaps
The heaps become:
max_heap = [(-10, 0), (-1, 1)]
min_heap = [(1, 1), (10, 0)]
Window adjustment: 10 - 1 = 9 > 5
Update
left_index
to 1Remove (-10, 0) from
max_heap
:max_heap = [(-1, 1)]
max_length
remains 1
Iteration 3 (nums[2] = 2):
Push (2, 2) to both heaps
The heaps become:
max_heap = [(-1, 1), (-2, 2)]
min_heap = [(1, 1), (2, 2), (10, 0)]
No window adjustment needed (2 - 1 = 1 <= 5)
Update
max_length
to 2
Iteration 4 (nums[3] = 4):
Push (4, 3) to both heaps
The heaps become:
max_heap = [(-1, 1), (-2, 2), (-4, 3)]
min_heap = [(1, 1), (2, 2), (4, 3), (10, 0)]
No window adjustment needed (4 - 1 = 3 <= 5)
Update
max_length
to 3
Iteration 5 (nums[4] = 7):
Push (7, 4) to both heaps
The heaps become:
max_heap = [(-1, 1), (-2, 2), (-4, 3), (-7, 4)]
min_heap = [(1, 1), (2, 2), (4, 3), (7, 4), (10, 0)]
Window adjustment: 7 - 1 = 6 > 5
Update
left_index
to 2Remove (1, 1) from
min_heap
:min_heap = [(2, 2), (4, 3), (7, 4), (10, 0)]
max_length
remains 3
Iteration 6 (nums[5] = 2):
Push (2, 5) to both heaps
The heaps become:
max_heap = [(-2, 2), (-4, 3), (-7, 4), (-2, 5)]
min_heap = [(2, 2), (4, 3), (7, 4), (10, 0)]
No window adjustment needed (7 - 2 = 5 <= 5)
Update
max_length
to 4
Loop Termination:
The loop ends after processing all elements in
nums
Final state:
left_index = 2
,max_length = 4
Visual Aid: Iteration Summary Table
Iteration
Current Number
Left Index
Current Length
Max Length
Max Heap (top 3)
Min Heap (top 3)
1
10
0
1
1
[(10, 0)]
[(10, 0)]
2
1
1
1
1
[(1, 1)]
[(1, 1), (10, 0)]
3
2
1
2
2
[(2, 2), (1, 1)]
[(1, 1), (10, 0), (2, 2)]
4
4
1
3
3
[(4, 3), (1, 1), (2, 2)]
[(1, 1), (4, 3), (2, 2)]
5
7
2
3
3
[(7, 4), (4, 3), (2, 2)]
[(2, 2), (4, 3), (7, 4)]
6
2
2
4
4
[(7, 4), (4, 3), (2, 2)]
[(2, 2), (2, 5), (7, 4)]
Result Calculation/Final Steps:
The algorithm maintains the max_length variable throughout the iterations
After processing all elements,
max_length
holds the length of the longest valid subarrayThe final result is
max_length = 4
, corresponding to the subarray [2, 4, 7, 2]
Approach 3: Sliding Window with Monotonic Queues
Understanding the Core Idea
The central concept of this solution is to leverage a sliding window approach combined with two monotonic queues (implemented using deques) to efficiently find the longest subarray that satisfies the given condition. This technique allows us to maintain a dynamic view of the current subarray while keeping track of its minimum and maximum elements in a highly efficient manner.
Sliding Window: The solution uses two pointers (
left_index
andright_index
) to define a window that expands and contracts as we iterate through the array.Monotonic Queues: Two deques are used: a monotonically decreasing queue for maximum values and a monotonically increasing queue for minimum values.
Dynamic Window Adjustment: As new elements are added, the window expands. If the condition is violated, the window contracts from the left side.
Code Walkthrough
Initialization:
max_queue = deque() min_queue = deque() left_index = 0Two empty deques are initialized:
max_queue
for maximum elements andmin_queue
for minimum elements.left_index
tracks the left boundary of the sliding window.Iterating Through the Array:
for right_index, num in enumerate(nums):This loop processes each element of the input array
nums
sequentially, usingright_index
as the current position.Maintaining Monotonic Queues:
while max_queue and num > max_queue[-1]: max_queue.pop() max_queue.append(num) while min_queue and num < min_queue[-1]: min_queue.pop() min_queue.append(num)These blocks maintain the monotonic property of the queues. For
max_queue
, we remove elements smaller than the current number from the right side before adding the current number. Formin_queue
, we remove elements larger than the current number.Adjusting Window:
if max_queue[0] - min_queue[0] > limit: if max_queue[0] == nums[left_index]: max_queue.popleft() if min_queue[0] == nums[left_index]: min_queue.popleft() left_index += 1This block checks if the difference between the maximum and minimum elements exceeds the limit. If so, it moves the left boundary of the window and updates the queues if necessary.
Result Calculation/Return:
return len(nums) - left_indexThe function returns the length of the longest valid subarray, which is the total length of the array minus the final position of the left index.
Complexity Analysis
Time Complexity:
, where is the length of the input array nums
. This is because each element is processed once and all operations on the deques (append
,pop
,pop-left
) are. Although there are nested loops, each element is pushed and popped at most once from each deque, ensuring linear time complexity.
Space Complexity:
, where is the length of the input array nums
. This is because in the worst case, the deques might need to store all elements of the input array simultaneously.
Example
Input:
Step-by-Step Walkthrough:
Initialization:
Initialize empty
max_queue
andmin_queue
as dequesSet
left_index = 0
Main Loop (Iterate through
nums
):Iteration 1 (
nums[0] = 10
):Update
max_queue
: Append 10,max_queue = [10]
Update
min_queue
: Append 10,min_queue = [10]
No window adjustment needed (10 - 10 = 0 <= 5)
Current window length: 1
Iteration 2 (
nums[1] = 1
):Update
max_queue
: Append 1,max_queue = [10, 1]
Update
min_queue
: Remove 10, append 1,min_queue = [1]
Window adjustment: 10 - 1 = 9 > 5
Remove 10 from
max_queue
:max_queue = [1]
Update
left_index
to 1
Current window length: 1
Iteration 3 (
nums[2] = 2
):Update
max_queue
: Remove 1, append 2,max_queue = [2]
Update
min_queue
: Append 2,min_queue = [1, 2]
No window adjustment needed (2 - 1 = 1 <= 5)
Current window length: 2
Iteration 4 (
nums[3] = 4
):Update
max_queue
: Remove 2, append 4,max_queue = [4]
Update
min_queue
: Append 4,min_queue = [1, 2, 4]
No window adjustment needed (4 - 1 = 3 <= 5)
Current window length: 3
Iteration 5 (
nums[4] = 7
):Update
max_queue
: Remove 4, append 7,max_queue = [7]
Update
min_queue
: Append 7,min_queue = [1, 2, 4, 7]
Window adjustment: 7 - 1 = 6 > 5
Remove 1 from
min_queue
:min_queue = [2, 4, 7]
Update
left_index
to 2
Current window length: 3
Iteration 6 (
nums[5] = 2
):Update
max_queue
: Append 2,max_queue = [7, 2]
Update
min_queue
: Remove 7 and 4, append 2,min_queue = [2, 2]
No window adjustment needed (7 - 2 = 5 <= 5)
Current window length: 4
Loop Termination:
The loop ends after processing all elements in
nums
Final state:
left_index = 2
Visual Aid: Iteration Summary Table
Iteration
Current Number
Left Index
Current Length
Max Queue
Min Queue
1
10
0
1
[10]
[10]
2
1
1
1
[1]
[1]
3
2
1
2
[2]
[1, 2]
4
4
1
3
[4]
[1, 2, 4]
5
7
2
3
[7]
[2, 4, 7]
6
2
2
4
[7, 2]
[2, 2]
Result Calculation/Final Steps:
The algorithm calculates the result as
len(nums) - left_index
Result = 6 - 2 = 4