Given an integer array arr[] that is sorted in increasing order and an integer k. Check whether it is possible to split arr[] into one or more subsequences such that both of the following conditions are true:
- Each subsequence is a consecutive increasing sequence (i.e. each integer is exactly one more than the previous integer).
- All subsequences have a length of k or more.
Examples:
Input: arr[] = [2, 2, 3, 3, 4, 5], k = 2
Output: true
Explanation: arr can be split into three subsequence of length k - [2, 3], [2, 3], [4, 5].Input: arr[] = [1, 1, 1, 1, 1], k = 4
Output: false
Explanation: It is impossible to split array into consecutive increasing subsequences of length 4 or more.
Try It Yourself
[Approach] Using MinHeap - O(n log(n)) Time and O(n) Space
The main idea is to use a min-heap and create a pair containing the element and its consecutive count, then push it into the min-heap. As we go through each element:
- If the element is consecutive to the top element of the heap, we increase its consecutive count.
- If it’s not consecutive, we check whether the top element’s count is at least k — if yes, we keep it; otherwise, return false.
- We continue this process of adding pairs and updating counts until all elements are processed.
- At the end, we ensure that all remaining subsequences in the heap have a length of at least k before returning true.
//Driver Code Starts
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
//Driver Code Ends
bool isPossible(vector<int>& arr, int k) {
auto comp = [](pair<int,int> a, pair<int,int> b) {
if(a.first == b.first)
// smaller length has higher priority
return a.second > b.second;
// smaller number has higher priority
return a.first > b.first;
};
// Min-heap stores pairs:
//{number, length of subsequence ending with this number}
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(comp)> pq(comp);
int i = 0;
while(i < arr.size()) {
if(pq.empty()) {
// If heap is empty, start a new subsequence
pq.push({arr[i], 1});
i++;
}
else {
auto top = pq.top();
if(arr[i] == top.first) {
// If current number same as top,
//start a new subsequence
pq.push({arr[i], 1});
i++;
}
else if(arr[i] == top.first + 1) {
// If current number is consecutive,
//extend the subsequence
pq.pop();
pq.push({arr[i], top.second + 1});
i++;
}
else {
// If current number is not
//consecutive, check if the top subsequence is valid
if(top.second < k) return false;
pq.pop();
}
}
}
// After processing all numbers,
//ensure all subsequences have length >= k
while(!pq.empty()) {
if(pq.top().second < k) return false;
pq.pop();
}
//Driver Code Starts
return true;
}
int main() {
vector<int> arr = {2, 2, 3, 3, 4, 5};
int k = 2;
if(isPossible(arr, k))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
//Driver Code Ends
//Driver Code Starts
import java.util.PriorityQueue;
import java.util.Comparator;
class GFG {
//Driver Code Ends
static boolean isPossible(int[] arr, int k) {
// Min-heap stores pairs: {number, length of
//subsequence ending with this number}
PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
if(a[0] == b[0])
// smaller length has higher priority
return a[1] - b[1];
// smaller number has higher priority
return a[0] - b[0];
}
});
int i = 0;
while(i < arr.length) {
if(pq.isEmpty()) {
// If heap is empty, start a new subsequence
pq.add(new int[]{arr[i], 1});
i++;
}
else {
int[] top = pq.peek();
if(arr[i] == top[0]) {
// If current number same as top,
//start a new subsequence
pq.add(new int[]{arr[i], 1});
i++;
}
else if(arr[i] == top[0] + 1) {
// If current number is consecutive,
//extend the subsequence
pq.poll();
pq.add(new int[]{arr[i], top[1] + 1});
i++;
}
else {
// If current number is not
//consecutive, check if top subsequence is valid
if(top[1] < k) return false;
pq.poll();
}
}
}
// After processing all numbers,
//ensure all subsequences have length >= k
while(!pq.isEmpty()) {
if(pq.peek()[1] < k) return false;
pq.poll();
}
return true;
}
//Driver Code Starts
public static void main(String[] args) {
int[] arr = {2, 2, 3, 3, 4, 5};
int k = 2;
if(isPossible(arr, k))
System.out.println("true");
else
System.out.println("false");
}
}
//Driver Code Ends
#Driver Code Starts
import heapq
#Driver Code Ends
def isPossible(arr, k):
# Min-heap stores pairs: (number, length of
# subsequence ending with this number)
pq = []
i = 0
while i < len(arr):
if not pq:
# If heap is empty, start a new subsequence
heapq.heappush(pq, (arr[i], 1))
i += 1
else:
top = pq[0]
if arr[i] == top[0]:
# If current number same as top,
# start a new subsequence
heapq.heappush(pq, (arr[i], 1))
i += 1
elif arr[i] == top[0] + 1:
# If current number is consecutive,
# extend the subsequence
heapq.heappop(pq)
heapq.heappush(pq, (arr[i], top[1] + 1))
i += 1
else:
# If current number is not consecutive
# check if the top subsequence is valid
if top[1] < k:
return False
heapq.heappop(pq)
# After processing all numbers,
# ensure all subsequences have length >= k
while pq:
if pq[0][1] < k:
return False
heapq.heappop(pq)
return True
#Driver Code Starts
if __name__ == "__main__":
arr = [2, 2, 3, 3, 4, 5]
k = 2
if isPossible(arr, k):
print("true")
else:
print("false")
#Driver Code Ends
//Driver Code Starts
using System;
using System.Collections.Generic;
class Heap {
private List<Tuple<int,int>> pq = new List<Tuple<int,int>>();
private bool Compare(Tuple<int,int> a, Tuple<int,int> b) {
// smaller number has higher priority
if(a.Item1 != b.Item1) return a.Item1 < b.Item1;
// smaller length has higher priority
return a.Item2 < b.Item2;
}
// push the element
public void Push(Tuple<int,int> t) {
pq.Add(t);
int i = pq.Count - 1;
while(i > 0) {
int parent = (i - 1) / 2;
if(Compare(pq[i], pq[parent])) {
var temp = pq[i];
pq[i] = pq[parent];
pq[parent] = temp;
i = parent;
}
else break;
}
}
// pop the element
public Tuple<int,int> Pop() {
if(pq.Count == 0) return null;
var ret = pq[0];
pq[0] = pq[pq.Count - 1];
pq.RemoveAt(pq.Count - 1);
int i = 0;
while(true) {
int left = 2*i + 1;
int right = 2*i + 2;
int smallest = i;
if(left < pq.Count && Compare(pq[left], pq[smallest])) smallest = left;
if(right < pq.Count && Compare(pq[right], pq[smallest])) smallest = right;
if(smallest != i)
{
var temp = pq[i];
pq[i] = pq[smallest];
pq[smallest] = temp;
i = smallest;
}
else break;
}
return ret;
}
public Tuple<int,int> Top() {
return pq.Count > 0 ? pq[0] : null;
}
public int Count() => pq.Count;
}
class GFG {
//Driver Code Ends
static bool isPossible(int[] arr, int k) {
// Min-heap stores pairs:
// {number, length of subsequence ending with this number}
Heap pq = new Heap();
int i = 0;
while(i < arr.Length) {
// If heap is empty, start a new subsequence
if(pq.Count() == 0) {
pq.Push(Tuple.Create(arr[i], 1));
i++;
}
else {
var top = pq.Top();
// If current number same as top,
//start a new subsequence
if(arr[i] == top.Item1) {
pq.Push(Tuple.Create(arr[i], 1));
i++;
}
// If current number is consecutive,
//extend the subsequenc
else if(arr[i] == top.Item1 + 1) {
var popped = pq.Pop();
pq.Push(Tuple.Create(arr[i], popped.Item2 + 1));
i++;
}
// If current number is not
//consecutive, check if the top subsequence is valid
else {
if(top.Item2 < k) return false;
pq.Pop();
}
}
}
// After processing all numbers,
//ensure all subsequences have length >= k
while(pq.Count() > 0) {
if(pq.Top().Item2 < k) return false;
pq.Pop();
}
return true;
}
//Driver Code Starts
static void Main() {
int[] arr = {2, 2, 3, 3, 4, 5};
int k = 2;
if(isPossible(arr, k))
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
//Driver Code Ends
//Driver Code Starts
function comparePair(a, b) {
if (a[0] === b[0]) {
// smaller length has higher priority
return a[1] - b[1];
}
// smaller number has higher priority
return a[0] - b[0];
}
class MinHeap {
constructor() {
this.data = [];
}
push(item) {
this.data.push(item);
this._heapifyUp();
}
pop() {
if (this.data.length === 0) return null;
if (this.data.length === 1) return this.data.pop();
const top = this.data[0];
this.data[0] = this.data.pop();
this._heapifyDown();
return top;
}
top() {
return this.data[0] || null;
}
size() {
return this.data.length;
}
_heapifyUp() {
let idx = this.data.length - 1;
while (idx > 0) {
let parent = Math.floor((idx - 1) / 2);
if (comparePair(this.data[parent], this.data[idx]) <= 0) break;
[this.data[parent], this.data[idx]] = [this.data[idx], this.data[parent]];
idx = parent;
}
}
_heapifyDown() {
let idx = 0;
const length = this.data.length;
while (true) {
let left = 2 * idx + 1;
let right = 2 * idx + 2;
let smallest = idx;
if (left < length && comparePair(this.data[left], this.data[smallest]) < 0)
smallest = left;
if (right < length && comparePair(this.data[right], this.data[smallest]) < 0)
smallest = right;
if (smallest === idx) break;
[this.data[idx], this.data[smallest]] = [this.data[smallest], this.data[idx]];
idx = smallest;
}
}
}
//Driver Code Ends
function isPossible(arr, k) {
// Min-heap stores pairs: {number, length of subsequence ending with this number}
const pq = new MinHeap();
let i = 0;
while (i < arr.length) {
if (pq.size() === 0) {
// If heap is empty, start a new subsequence
pq.push([arr[i], 1]);
i++;
} else {
const top = pq.top();
if (arr[i] === top[0]) {
// If current number same as top,
//start a new subsequence
pq.push([arr[i], 1]);
i++;
} else if (arr[i] === top[0] + 1) {
// If current number is consecutive,
//extend the subsequence
pq.pop();
pq.push([arr[i], top[1] + 1]);
i++;
} else {
// If current number is not consecutive,
//check if the top subsequence is valid
if (top[1] < k) return false;
pq.pop();
}
}
}
// After processing all numbers,
//ensure all subsequences have length >= k
while (pq.size() > 0) {
const top = pq.pop();
if (top[1] < k) return false;
}
return true;
}
//Driver Code Starts
// Driver code
const arr = [2, 2, 3, 3, 4, 5];
const k = 2;
console.log(isPossible(arr, k) ? "true" : "false");
//Driver Code Ends
Output
true