{x}
blog image

Divide Array in Sets of K Consecutive Numbers

Given an array of integers nums and a positive integer k, check whether it is possible to divide this array into sets of k consecutive numbers.

Return true if it is possible. Otherwise, return false.

 

Example 1:

Input: nums = [1,2,3,3,4,4,5,6], k = 4
Output: true
Explanation: Array can be divided into [1,2,3,4] and [3,4,5,6].

Example 2:

Input: nums = [3,2,1,2,3,4,3,4,5,9,10,11], k = 3
Output: true
Explanation: Array can be divided into [1,2,3] , [2,3,4] , [3,4,5] and [9,10,11].

Example 3:

Input: nums = [1,2,3,4], k = 3
Output: false
Explanation: Each array should be divided in subarrays of size 3.

 

Constraints:

  • 1 <= k <= nums.length <= 105
  • 1 <= nums[i] <= 109

 

Note: This question is the same as 846: https://leetcode.com/problems/hand-of-straights/

Solution Explanation for Divide Array in Sets of K Consecutive Numbers

This problem asks whether we can partition an array into sets of k consecutive numbers. The optimal solution uses a combination of hashing (to count element occurrences) and sorting (to efficiently find consecutive sequences).

Approach:

  1. Counting Occurrences: We first count the occurrences of each number in the input array nums using a hash map (dictionary in Python). This allows for efficient lookups of element frequencies.

  2. Sorting: We sort the input array nums. Sorting ensures that we process numbers in ascending order, making it easier to find consecutive sequences.

  3. Greedy Approach: We iterate through the sorted array. For each number v:

    • If v is present (count > 0) in the hash map:
    • We check if the next k-1 consecutive numbers (v+1, v+2, ..., v+k-1) are also present and have counts greater than 0.
    • If all k consecutive numbers are found, we decrement their counts in the hash map. If a count reaches 0, we remove the entry from the map to avoid redundant checks.
    • If at any point a consecutive number is missing (count is 0), we know that a partition into sets of k consecutive numbers is impossible, and we return false.
  4. Success: If we successfully process all numbers in the sorted array without finding any missing consecutive numbers, it means we can partition the array as required, and we return true.

Time Complexity:

  • Sorting the array takes O(n log n) time, where n is the length of the input array.
  • Iterating through the sorted array and checking for consecutive numbers takes O(n) time in the best case (all numbers form consecutive sets) and O(n*k) time in the worst case (many scattered numbers). However, since k is significantly smaller than n, this is still dominated by O(n log n).

Therefore, the overall time complexity is O(n log n).

Space Complexity:

  • The hash map to store element counts takes O(n) space in the worst case (all numbers are unique).
  • The sorted array (if we create a copy) also takes O(n) space.

Therefore, the overall space complexity is O(n).

Code Examples:

The code examples below demonstrate the solution in Python, Java, C++, and Go. They all follow the same algorithmic approach.

Python

from collections import Counter
 
def isPossibleDivide(nums, k):
    if len(nums) % k != 0:  # Check if partition is possible
        return False
    count = Counter(nums)
    for num in sorted(nums):
        if count[num] > 0:
            for i in range(num, num + k):
                if count[i] == 0:
                    return False
                count[i] -= 1
    return True
 

Java

import java.util.*;
 
class Solution {
    public boolean isPossibleDivide(int[] nums, int k) {
        if (nums.length % k != 0) return false;
        Map<Integer, Integer> count = new HashMap<>();
        for (int num : nums) {
            count.put(num, count.getOrDefault(num, 0) + 1);
        }
        Arrays.sort(nums);
        for (int num : nums) {
            if (count.get(num) > 0) {
                for (int i = num; i < num + k; i++) {
                    if (count.getOrDefault(i, 0) == 0) return false;
                    count.put(i, count.get(i) - 1);
                }
            }
        }
        return true;
    }
}

C++

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
 
using namespace std;
 
bool isPossibleDivide(vector<int>& nums, int k) {
    if (nums.size() % k != 0) return false;
    map<int, int> count;
    for (int num : nums) {
        count[num]++;
    }
    sort(nums.begin(), nums.end());
    for (int num : nums) {
        if (count[num] > 0) {
            for (int i = num; i < num + k; i++) {
                if (count.count(i) == 0 || count[i] == 0) return false;
                count[i]--;
            }
        }
    }
    return true;
}

Go

import (
	"sort"
)
 
func isPossibleDivide(nums []int, k int) bool {
	if len(nums)%k != 0 {
		return false
	}
	count := make(map[int]int)
	for _, num := range nums {
		count[num]++
	}
	sort.Ints(nums)
	for _, num := range nums {
		if count[num] > 0 {
			for i := num; i < num+k; i++ {
				if count[i] == 0 {
					return false
				}
				count[i]--
			}
		}
	}
	return true
}

This detailed explanation, along with the code examples, provides a comprehensive understanding of how to solve the "Divide Array in Sets of K Consecutive Numbers" problem efficiently. Remember to handle the edge case where the array length is not divisible by k.