Facebook Pixel

3184. Count Pairs That Form a Complete Day I

EasyArrayHash TableCounting
Leetcode Link

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:

  1. Traverse the hours array.
  2. For each hour x, calculate how many previous hours would pair with x to complete a day (their total sum is a multiple of 24). The number we are looking for is (24 - (x % 24)) % 24.
  3. Use the cnt hash table or array to find how many such numbers have already been counted and add this count to our answer.
  4. 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

  1. Initialize a Counter: We start by initializing a Counter object named cnt. This will be used to count how many times each remainder (obtained by taking modulo 24 of each hour) appears as we iterate through the hours array.

  2. Iterate Through the hours Array: We loop over each element x in the hours 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 pairs i, j where i < j.

    • Update the Counter: Increment the count for the current remainder x % 24 in cnt to reflect its occurrence.

  3. 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 Evaluator

Example 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.

  1. Initialize a Counter: We start with an empty Counter called cnt. We'll also initialize a variable ans to store the count of valid pairs.

  2. 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 to ans.
      • Update the Counter: cnt now becomes {8: 1}.
    • Second Hour (x = 16):

      • Calculate the complement: (24 - (16 % 24)) % 24 = 8.
      • cnt[8] is 1, meaning we have seen one 8 before. So, we add 1 to ans making ans = 1.
      • Update the Counter: cnt now becomes {8: 1, 16: 1}.
    • Third Hour (x = 8):

      • Calculate the complement: (24 - (8 % 24)) % 24 = 16.
      • cnt[16] is 1, so we add 1 to ans making ans = 2.
      • Update the Counter: cnt now becomes {8: 2, 16: 1}.
    • Fourth Hour (x = 16):

      • Calculate the complement: (24 - (16 % 24)) % 24 = 8.
      • cnt[8] is 2, meaning we've seen two 8s before. So, we add 2 to ans, making ans = 4.
      • Update the Counter: cnt now becomes {8: 2, 16: 2}.
  3. Return the Result: After processing the entire hours array, the total number of valid pairs is 4. 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.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

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

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More