3184. Count Pairs That Form a Complete Day I
Problem Description
Given an integer array hours
representing times in hours, return an integer denoting the number of pairs i
, j
where i < j
and hours[i] + hours[j]
forms a complete day.
A complete day is defined as a time duration that is an exact multiple of 24 hours.
For example, 1 day is 24 hours, 2 days is 48 hours, 3 days is 72 hours, and so on.
Intuition
To solve the problem, we focus on finding pairs in the hours
array where their sum is divisible by 24. A simple way to determine if a sum is divisible by 24 is to check if the sum modulo 24 equals zero.
To facilitate this, we use a hash table, or array, called cnt
to store the count of each remainder when each element of the hours
array is divided by 24. This will help us track how many numbers have a specific remainder when divided by 24.
The steps are as follows:
- Traverse the
hours
array. - For each hour
x
, calculate how many previous hours would pair withx
to complete a day (their total sum is a multiple of 24). The number we are looking for is(24 - (x % 24)) % 24
. - Use the
cnt
hash table or array to find how many such numbers have already been counted and add this count to our answer. - Finally, update the
cnt
with the remainder of the current hour modulo 24.
This method is efficient because it allows us to track potential pairs in constant time using the hash table, making it much faster than a nested loop approach.
Solution Approach
To solve the problem efficiently, we employ a counting technique that utilizes a Counter
or hash table to keep track of the occurrences of each hour modulo 24. This approach helps us determine the number of valid pairs without considering every possible combination, which would be computationally expensive.
Step-by-Step Explanation
-
Initialize a Counter: We start by initializing a
Counter
object namedcnt
. This will be used to count how many times each remainder (obtained by taking modulo 24 of each hour) appears as we iterate through thehours
array. -
Iterate Through the
hours
Array: We loop over each elementx
in thehours
list. During each iteration, we perform the following actions:-
Calculate the Complement: Determine the complement remainder required for
x
to finish a complete day when paired. This is calculated as(24 - (x % 24)) % 24
. This expression effectively finds the opposite remainder needed to make the pair sum a multiple of 24. -
Count Valid Pairs: Use
cnt
to find how often this complement remainder has appeared before the current hour. These occurrences count the number of valid pairsi, j
wherei < j
. -
Update the Counter: Increment the count for the current remainder
x % 24
incnt
to reflect its occurrence.
-
-
Return the Result: After iterating through all the hours, the variable
ans
holds the total number of valid pairs that satisfy the problem's condition.
This counting approach is efficient and ensures that the solution operates in linear time relative to the size of the hours
array, i.e., O(n)
complexity.
Here's how the code implements the above logic:
class Solution:
def countCompleteDayPairs(self, hours: List[int]) -> int:
cnt = Counter()
ans = 0
for x in hours:
ans += cnt[(24 - (x % 24)) % 24]
cnt[x % 24] += 1
return ans
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's illustrate the solution approach using a small example.
Consider the hours
array: [8, 16, 8, 16]
.
Our goal is to find the number of pairs (i, j)
such that the sum of hours[i] + hours[j]
is an exact multiple of 24, and i < j
.
-
Initialize a Counter: We start with an empty
Counter
calledcnt
. We'll also initialize a variableans
to store the count of valid pairs. -
Iterate Through the
hours
Array:-
First Hour (x = 8):
- Calculate the complement:
(24 - (8 % 24)) % 24 = 16
. cnt[16]
is 0 at this point, so no valid pairs are added toans
.- Update the Counter:
cnt
now becomes{8: 1}
.
- Calculate the complement:
-
Second Hour (x = 16):
- Calculate the complement:
(24 - (16 % 24)) % 24 = 8
. cnt[8]
is 1, meaning we have seen one8
before. So, we add 1 toans
makingans = 1
.- Update the Counter:
cnt
now becomes{8: 1, 16: 1}
.
- Calculate the complement:
-
Third Hour (x = 8):
- Calculate the complement:
(24 - (8 % 24)) % 24 = 16
. cnt[16]
is 1, so we add 1 toans
makingans = 2
.- Update the Counter:
cnt
now becomes{8: 2, 16: 1}
.
- Calculate the complement:
-
Fourth Hour (x = 16):
- Calculate the complement:
(24 - (16 % 24)) % 24 = 8
. cnt[8]
is 2, meaning we've seen two8
s before. So, we add 2 toans
, makingans = 4
.- Update the Counter:
cnt
now becomes{8: 2, 16: 2}
.
- Calculate the complement:
-
-
Return the Result: After processing the entire
hours
array, the total number of valid pairs is4
. This is the result that meets the condition of sum being a multiple of 24.
class Solution:
def countCompleteDayPairs(self, hours: List[int]) -> int:
cnt = Counter()
ans = 0
for x in hours:
ans += cnt[(24 - (x % 24)) % 24]
cnt[x % 24] += 1
return ans
# Using the walkthrough example:
s = Solution()
print(s.countCompleteDayPairs([8, 16, 8, 16])) # Output: 4
Solution Implementation
1from typing import List
2from collections import Counter
3
4class Solution:
5 def countCompleteDayPairs(self, hours: List[int]) -> int:
6 # Initialize a counter to track remainders
7 remainder_count = Counter()
8 # Variable to store the number of valid pairs
9 complete_day_pairs = 0
10
11 # Iterate through each hour in the list
12 for hour in hours:
13 # Calculate the remainder needed to form a full 24-hour cycle
14 # with the current hour's remainder
15 needed_remainder = (24 - (hour % 24)) % 24
16 # Add the number of times this needed remainder has been seen
17 # to the total pair count
18 complete_day_pairs += remainder_count[needed_remainder]
19 # Increment the count of the current hour's remainder
20 remainder_count[hour % 24] += 1
21
22 # Return the number of complete day pairs
23 return complete_day_pairs
24
1class Solution {
2 public int countCompleteDayPairs(int[] hours) {
3 // Array to count occurrences of each modulus (0-23) over the 24-hour period
4 int[] count = new int[24];
5
6 // Initialize the result to count the number of complete pairs
7 int result = 0;
8
9 // Iterate over each hour in the input array
10 for (int hour : hours) {
11 // Calculate the complementary modulus needed to complete a 24-hour cycle
12 // Add to the result the number of hours with the complementary modulus seen so far
13 result += count[(24 - hour % 24) % 24];
14
15 // Increase the count of the current hour's modulus
16 ++count[hour % 24];
17 }
18
19 // Return the total number of complete day pairs
20 return result;
21 }
22}
23
1class Solution {
2public:
3 int countCompleteDayPairs(vector<int>& hours) {
4 int count[24] = {}; // Array to store the count of remainders when hours are divided by 24 (0 to 23)
5 int completeDayPairs = 0; // Initialize the number of complete day pairs to zero
6
7 // Iterate over each hour in the vector
8 for (int hour : hours) {
9 // Calculate complement to reach 24, taking mod to handle wrap-around cases
10 completeDayPairs += count[(24 - hour % 24) % 24];
11
12 // Increment the count at the index of the current hour's remainder
13 ++count[hour % 24];
14 }
15
16 return completeDayPairs; // Return the total number of complete day pairs
17 }
18};
19
1// Function to count complete day pairs in the given array of hours
2function countCompleteDayPairs(hours: number[]): number {
3 // Initialize an array to keep count of each remainder when divided by 24
4 const cnt: number[] = Array(24).fill(0);
5 // Variable to store the total number of complete day pairs
6 let ans: number = 0;
7
8 // Iterate through each hour in the given array
9 for (const x of hours) {
10 // Find the complement remainder needed to complete 24 hours and add the count of such remainders
11 ans += cnt[(24 - (x % 24)) % 24];
12 // Increment the count of the current hour's remainder
13 ++cnt[x % 24];
14 }
15
16 // Return the total number of complete day pairs
17 return ans;
18}
19
Time and Space Complexity
The code iterates over each element in the hours
list once, performing constant-time operations per element, which results in a time complexity of O(n)
, where n
is the length of the array hours
.
For space complexity, a Counter
is used to store values based on the remainder when each hour is divided by 24
. Since there are at most 24
unique remainders (from 0
to 23
), the space complexity is O(24)
, which simplifies to O(1)
as it does not depend on the size of the input.
Learn more about how to find time and space complexity quickly.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!