Given an integer array arr[], where each element represents the number written on a ball, and an integer k, determine whether it's possible to rearrange all the balls into groups of size k such that each group contains k consecutive numbers.
Examples:
Input: arr[] = [10, 1, 2, 11], k = 2
Output: true
Explanation: The hand can be rearranged as [1, 2], [10, 11]. There are two groups of size 2. Each group has 2 consecutive cards.Input: arr[] = [1, 2, 3, 4, 5], k = 2
Output: false
Explanation: The hand cannot be rearranged into groups of 2, since there are 5 cards, and 5 cards cannot be divided into groups of 2.
Table of Content
[Approach 1] Sorting then Searching for k consecutive elements - O(n*log(n)) time and O(1) space
The main idea is to group the balls into sequences of
kconsecutive numbers without reusing any balls. The arr is first sorted to simplify finding consecutive groups. For each unused ball, the code tries to form a group ofkconsecutive balls by scanning forward. Balls are marked as-1once used, and if any group can't be formed, the function returnsfalse.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool validgroup(vector<int> &arr, int k) {
// Sort the arr to make consecutive grouping easier
sort(arr.begin(), arr.end());
// Traverse the sorted arr
for (int i = 0; i < arr.size(); i++) {
// Skip if the card is already used
if (arr[i] == -1) continue;
// To track how many cards we added to the current group
int count = 0;
// Starting value of current group
int curr = arr[i];
// Try to form a group of size 'k'
for (int j = i; j < arr.size(); j++) {
if (arr[j] == curr) {
count++;
// Move to next consecutive card
curr++;
// Mark this card as used
arr[j] = -1;
}
if (count == k) break;
}
// If we couldn't form a full group of size k, return false
if (count != k) return false;
}
// All cards successfully grouped
return true;
}
int main() {
vector<int> arr = {10, 1, 2, 11};
int k = 3;
// Check and print result
if (validgroup(arr, k)) {
cout << "true" << endl;
} else {
cout << "false" << endl;
}
return 0;
}
import java.util.Arrays;
class GfG{
public static boolean validgroup(int[] arr, int k) {
// Sort the arr to make consecutive grouping easier
Arrays.sort(arr);
// Traverse the sorted arr
for (int i = 0; i < arr.length; i++) {
// Skip if the card is already used
if (arr[i] == -1) continue;
// To track how many cards we added to the current group
int count = 0;
// Starting value of current group
int curr = arr[i];
// Try to form a group of size 'k'
for (int j = i; j < arr.length; j++) {
if (arr[j] == curr) {
count++;
// Move to next consecutive card
curr++;
// Mark this card as used
arr[j] = -1;
}
if (count == k) break;
}
// If we couldn't form a full group of size k, return false
if (count != k) return false;
}
// All cards successfully grouped
return true;
}
public static void main(String[] args) {
int[] arr = {10, 1, 2, 11};
int k = 3;
// Check and print result
if (validgroup(arr, k)) {
System.out.println("true");
} else {
System.out.println("false");
}
}
}
def validgroup(arr, k):
# Sort the arr to make consecutive grouping easier
arr.sort()
# Traverse the sorted arr
for i in range(len(arr)):
# Skip if the card is already used
if arr[i] == -1:
continue
# To track how many cards we added to the current group
count = 0
# Starting value of current group
curr = arr[i]
# Try to form a group of size 'k'
for j in range(i, len(arr)):
if arr[j] == curr:
count += 1
# Move to next consecutive card
curr += 1
# Mark this card as used
arr[j] = -1
if count == k:
break
# If we couldn't form a full group of size k, return False
if count != k:
return False
# All cards successfully grouped
return True
if __name__ == "__main__":
arr = [10, 1, 2, 11]
k = 3
# Check and print result
if validgroup(arr, k):
print("true")
else:
print("false")
using System;
class GfG {
public static bool validgroup(int[] arr, int k) {
// Sort the array to make consecutive grouping easier
Array.Sort(arr);
// Create a boolean array to mark used elements
bool[] used = new bool[arr.Length];
for (int i = 0; i < arr.Length; i++) {
// Skip if this number is already used in a group
if (used[i]) continue;
// Starting value of the current group
int curr = arr[i];
// Track how many numbers we've added to this group
int count = 0;
// Try to form a group of size k starting from current index
for (int j = 0; j < arr.Length; j++) {
if (!used[j] && arr[j] == curr) {
used[j] = true;
curr++;
count++;
}
if (count == k) break;
}
// If we couldn't form a full group of size k, return false
if (count != k) return false;
}
// All numbers successfully grouped
return true;
}
static void Main() {
int[] arr = {10, 1, 2, 11};
int k = 3;
// Check and print result
if (validgroup(arr, k)) {
Console.WriteLine("true");
} else {
Console.WriteLine("false");
}
}
}
function validgroup(arr, k) {
// Sort the arr to make consecutive grouping easier
arr.sort((a, b) => a - b);
// Traverse the sorted arr
for (let i = 0; i < arr.length; i++) {
// Skip if the card is already used
if (arr[i] === -1) continue;
// To track how many cards we added to the current group
let count = 0;
// Starting value of current group
let curr = arr[i];
// Try to form a group of size 'k'
for (let j = i; j < arr.length; j++) {
if (arr[j] === curr) {
count++;
// Move to next consecutive card
curr++;
// Mark this card as used
arr[j] = -1;
}
if (count === k) break;
}
// If we couldn't form a full group of size k, return false
if (count !== k) return false;
}
// All cards successfully grouped
return true;
}
// Driver Code
let arr = [10, 1, 2, 11];
let k = 3;
// Check and print result
if (validgroup(arr, k)) {
console.log("true");
} else {
console.log("false");
}
Output
false
Time Complexity: O(n log n), due to sorting the array, while the rest of the logic runs in linear time as each element is visited at most once.
Auxiliary Space: O(1) extra space (in-place modifications using -1 as marker), ignoring input size. If input modification is not allowed, space becomes O(n) for a visited array or frequency map.
[Approach 2] Using Hash Map - O(n*log n) time and O(n) space
The idea is to store the frequency of each value in an ordered hash map. Then starting for each value and its frequency, check if consecutive values up to value + k - 1 have at least the same frequency.
Step-by-Step Approach:
- Store the frequency of each value in an ordered hash map. Then start traversing the hash map from minimum value. We want to process the minimum values first in order to maintain the consecutive value order and ensure that no value is left unused.
- For each value v and its frequency f, if the frequency is 0, it means that this value has already been used to create other groups, so continue.
- Otherwise, starting from value = v +1 to value = v + k - 1, check if the frequency of these values is at least f. If yes, decrease the frequency by f. If not, return false as it is not possible to create consecutive groups starting from value v.
- Return true if all values are processed.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
bool validgroup(vector<int> &arr, int k) {
int n = arr.size();
map<int, int> freqMap;
// Store the frequency of each value
for (int val : arr) {
freqMap[val]++;
}
// Starting from minimum value, try to form consecutive groups
for (auto p : freqMap) {
int val = p.first;
int freq = p.second;
// Skip if all cards of this value are already used
if (freq == 0) continue;
// Try to form a group of 'k' starting from 'val'
for (int i = 1; i < k; i++) {
int nextVal = val + i;
// Check if there are enough cards for the next value
if (freqMap[nextVal] < freq) {
return false;
}
// Deduct the used cards
freqMap[nextVal] -= freq;
}
}
return true;
}
int main() {
vector<int> arr = {10, 1, 2, 11};
int k = 3;
if (validgroup(arr, k)) {
cout << "true" << endl;
} else {
cout << "false" << endl;
}
return 0;
}
import java.util.TreeMap;
class GfG {
static boolean validgroup(int[] arr, int k) {
int n = arr.length;
TreeMap<Integer, Integer> map = new TreeMap<>();
// Store the frequency of each value
for (int val: arr) map.put(val, map.getOrDefault(val, 0) + 1);
// Starting from minimum value, check if
// it is possible to create consecutive
// group with values upto value + k - 1.
for (var p: map.entrySet()) {
int val = p.getKey(), freq = p.getValue();
// If frequency is 0, it means this value
// has already been used in another group
if (freq == 0) continue;
// If there exists x occurences of val, then
// we need atleast x occurences of val+1, val+2
// , val+3, .... val+k-1.
for (int i = 1; i< k; i++) {
int v = val + i;
int f = map.getOrDefault(v, 0);
// If frequency is less than freq
if (f < freq) {
return false;
}
map.put(v, f - freq);
}
}
return true;
}
public static void main(String[] args) {
int[] arr = {10, 1, 2, 11};
int k = 3;
if (validgroup(arr, k)) {
System.out.println("true");
}
else {
System.out.println("false");
}
}
}
from collections import defaultdict
def validgroup(arr, k):
n = len(arr)
map = defaultdict(int)
# Store the frequency of each value
for val in arr: map[val] += 1
# Starting from minimum value, check if
# it is possible to create consecutive
# group with values upto value + k - 1.
for val in sorted(map.keys()):
freq = map.get(val, 0)
# If frequency is 0, it means this value
# has already been used in another group
if freq == 0: continue
# If there exists x occurences of val, then
# we need atleast x occurences of val+1, val+2
# , val+3, .... val+k-1.
for i in range(1, k):
v = val + i
f = map.get(v, 0)
# If frequency is less than freq
if f < freq:
return False
map[v] -= freq
return True
if __name__ == "__main__":
arr = [10, 1, 2, 11]
k = 3
if validgroup(arr, k):
print("true")
else:
print("false")
using System;
using System.Collections.Generic;
class GfG {
static bool validgroup(int[] arr, int k) {
int n = arr.Length;
Dictionary<int, int> map = new Dictionary<int, int>();
// Store the frequency of each value
foreach (int val in arr) {
if (map.ContainsKey(val)) map[val]++;
else map[val] = 1;
}
// Get all unique keys and sort them
List<int> keys = new List<int>(map.Keys);
keys.Sort();
// Starting from minimum value, check if
// it is possible to create consecutive
// groups with values up to value + k - 1
foreach (int val in keys) {
int freq = map[val];
// If frequency is 0, it means this value
// has already been used in another group
if (freq == 0) continue;
// Try to form a group of size k starting from val
for (int i = 1; i < k; i++) {
int nextVal = val + i;
int nextFreq = map.ContainsKey(nextVal) ? map[nextVal] : 0;
if (nextFreq < freq) return false;
map[nextVal] = nextFreq - freq;
}
}
return true;
}
static void Main() {
int[] arr = {10, 1, 2, 11};
int k = 3;
if (validgroup(arr, k)) {
Console.WriteLine("true");
} else {
Console.WriteLine("false");
}
}
}
function validgroup(arr, k) {
if (arr.length % k !== 0) return false;
let map = new Map();
// Store the frequency of each value
for (let val of arr) {
map.set(val, (map.get(val) || 0) + 1);
}
// Sort all keys (unique values)
let sortedKeys = [...map.keys()].sort((a, b) => a - b);
for (let val of sortedKeys) {
let freq = map.get(val);
if (freq === 0) continue;
// Try to form group of size k starting from val
for (let i = 0; i < k; i++) {
let currVal = val + i;
let currFreq = map.get(currVal) || 0;
if (currFreq < freq) return false;
map.set(currVal, currFreq - freq);
}
}
return true;
}
let arr = [10, 1, 2, 11];
let k = 3;
if (validgroup(arr, k)) {
console.log("true");
}
else {
console.log("false");
}
Output
false