Talentd
FleetCode
Make and follow sheets.Sign in

Minimum Operations to Make the Array K-Increasing solution and explanation

HardArrayBinary Search6 min read41.1% acceptanceUpdated 9 Apr 2026
Minimum Operations to Make the Array K-Increasing | Leetcode 2111 | Live coding session | LIS 🔥🔥🔥Coding Decoded · 13:10 · 2K viewsWatch on YouTube
8 more videos on this problem
  1. Minimum Operations to Make the Array K-Increasing | Leetcode 2111 | Live coding session | LIS 🔥🔥🔥Coding Decoded · 13:10 · 2K views
  2. Minimum Operations to Make the Array K Increasing | Leetcode #2111Techdose · 16:08 · 1K views
  3. (Hard) Minimum Operations to Make the Array K-Increasing | Leetcode Weekly Contest 272Hitesh Tripathi · 13:48 · 823 views
  4. 【每日一题】LeetCode 2111. Minimum Operations to Make the Array K-IncreasingHuifeng Guan · 26:05 · 754 views
  5. 2111. Minimum Operations to Make the Array K-Increasing (Leetcode Hard)Programming Live with Larry · 14:42 · 573 views
  6. Leetcode: Minimum Operations to Make the Array K-IncreasingCoding For Dummies · 14:54 · 149 views
  7. Leetcode 2111 Minimum Operations to Make the Array K-Increasing. Non descending array, binary searchInterview Ready · 11:09 · 128 views
  8. 2111 Minimum Operations to Make the Array K IncreasingMath Geeks · 9:45 · 94 views
  9. LeetCode 2111: Minimum Operations to Make the Array K-IncreasingAlitaCode · 30:57 · 1 view

The problem

You are given a 0-indexed array arr consisting of n positive integers, and a positive integer k.

The array arr is called K-increasing if arr[i-k] <= arr[i] holds for every index i, where k <= i <= n-1.

  • For example, arr = [4, 1, 5, 2, 6, 2] is K-increasing for k = 2 because:
    • arr[0] <= arr[2] (4 <= 5)
    • arr[1] <= arr[3] (1 <= 2)
    • arr[2] <= arr[4] (5 <= 6)
    • arr[3] <= arr[5] (2 <= 2)
  • However, the same arr is not K-increasing for k = 1 (because arr[0] > arr[1]) or k = 3 (because arr[0] > arr[3]).

In one operation, you can choose an index i and change arr[i] into any positive integer.

Return the minimum number of operations required to make the array K-increasing for the given k.

Example 1:

Input: arr = [5,4,3,2,1], k = 1
Output: 4
Explanation:
For k = 1, the resultant array has to be non-decreasing.
Some of the K-increasing arrays that can be formed are [5,6,7,8,9], [1,1,1,1,1], [2,2,3,4,4]. All of them require 4 operations.
It is suboptimal to change the array to, for example, [6,7,8,9,10] because it would take 5 operations.
It can be shown that we cannot make the array K-increasing in less than 4 operations.

Example 2:

Input: arr = [4,1,5,2,6,2], k = 2
Output: 0
Explanation:
This is the same example as the one in the problem description.
Here, for every index i where 2 <= i <= 5, arr[i-2] <= arr[i].
Since the given array is already K-increasing, we do not need to perform any operations.

Example 3:

Input: arr = [4,1,5,2,6,2], k = 3
Output: 2
Explanation:
Indices 3 and 5 are the only ones not satisfying arr[i-3] <= arr[i] for 3 <= i <= 5.
One of the ways we can make the array K-increasing is by changing arr[3] to 4 and arr[5] to 5.
The array will now be [4,1,5,4,6,5].
Note that there can be other ways to make the array K-increasing, but none of them require less than 2 operations.

Constraints:

  • 1 <= arr.length <= 105
  • 1 <= arr[i], k <= arr.length

Approach overview

Problem Overview: You receive an integer array arr and an integer k. The array is k-increasing if every element satisfies arr[i] >= arr[i-k] for all valid i. You can change any value in the array. The task is to compute the minimum number of operations required to make the array satisfy this constraint.

Approach 1: Longest Non-Decreasing Subsequence per Group (DP) (Time: O(n²), Space: O(n))

Elements that interact with each other are spaced exactly k apart. This means the array naturally splits into k independent subsequences: indices i, i+k, i+2k.... Each subsequence must be non-decreasing. For a subsequence of length m, the minimum operations equal m - LNDS (longest non-decreasing subsequence). A straightforward dynamic programming solution computes LNDS by checking all previous elements and extending valid subsequences. This takes O(m²) time per group and O(n²) overall in the worst case. The idea is conceptually simple and useful for understanding the transformation into subsequence problems.

Approach 2: Divide into K Subsequences + LIS with Binary Search (Time: O(n log n), Space: O(n))

A faster solution uses the same decomposition into k independent subsequences but computes the longest non-decreasing subsequence using the classic patience sorting technique with binary search. For each subsequence, maintain a tails array where tails[x] stores the smallest ending value of a non-decreasing subsequence of length x+1. Iterate through the subsequence and place each value using an upper_bound-style binary search so equal values are allowed (non-decreasing condition). This reduces the LNDS computation to O(m log m) for a subsequence of length m. Summed across all groups, the complexity becomes O(n log(n/k)), which is effectively O(n log n).

This approach relies on two observations: the k-gap constraint isolates dependencies into separate chains, and minimizing modifications is equivalent to keeping the longest valid subsequence. The remaining elements in each chain must be modified. Using binary search dramatically speeds up subsequence computation compared to quadratic DP.

Key concepts involved include array partitioning with modular indexing, subsequence optimization, and efficient searching using binary search on top of an array-based structure.

Recommended for interviews: The LIS + binary search solution is what interviewers expect. Recognizing that the constraint splits the problem into k independent sequences shows strong problem decomposition skills. Explaining the quadratic LNDS approach first demonstrates understanding, while implementing the O(n log n) optimization shows mastery of subsequence techniques.

Approach 1: Divide and Solve Subproblems Using LIS

The first approach is to divide the original array into k-length subsequences and solve each of these subsequences independently. By focusing on making each subsequence non-decreasing, we can apply the concept of the Longest Increasing Subsequence (LIS). The transformation of each subsequence into the LIS will give insight into the minimum operations required.

Steps:

  1. Divide the array into k-length subsequences.
  2. For each subsequence, find the LIS. The number of changes required for each subsequence is the size of the sequence minus the length of its LIS.
  3. Sum up the changes required for all subsequences.
from bisect import bisect_right

def min_operations(arr, k):
    n = len(arr)
    total_operations = 0
    for start in range(k):
        dp = []
        for i in range(start, n, k):
            pos = bisect_right(dp, arr[i])
            if pos < len(dp):
                dp[pos] = arr[i]
            else:
                dp.append(arr[i])
        seq_length = (n - start - 1) // k + 1
        total_operations += seq_length - len(dp)
    return total_operations

arr = [4, 1, 5, 2, 6, 2]
k = 3
print("Minimum operations:", min_operations(arr, k))
import java.util.ArrayList;
import java.util.Collections;

public class KIncreasing {
    public static int minOperations(int[] arr, int k) {
        int n = arr.length;
        int totalOperations = 0;
        for (int start = 0; start < k; start++) {
            ArrayList<Integer> dp = new ArrayList<>();
            for (int i = start; i < n; i += k) {
                int pos = Collections.binarySearch(dp, arr[i]);
                if (pos < 0) pos = -pos - 1;
                if (pos >= dp.size())
                    dp.add(arr[i]);
                else
                    dp.set(pos, arr[i]);
            }
            int seqLength = (n - start - 1) / k + 1;
            totalOperations += seqLength - dp.size();
        }
        return totalOperations;
    }

    public static void main(String[] args) {
        int[] arr = {4, 1, 5, 2, 6, 2};
        int k = 3;
        System.out.println("Minimum operations: " + minOperations(arr, k));
    }
}
#include <iostream>
#include <vector>
#include <algorithm>

int minOperations(std::vector<int>& arr, int k) {
    int n = arr.size();
    int totalOperations = 0;
    for (int start = 0; start < k; start++) {
        std::vector<int> dp;
        for (int i = start; i < n; i += k) {
            auto it = std::upper_bound(dp.begin(), dp.end(), arr[i]);
            if (it == dp.end())
                dp.push_back(arr[i]);
            else
                *it = arr[i];
        }
        int seqLength = (n - start - 1) / k + 1;
        totalOperations += seqLength - dp.size();
    }
    return totalOperations;
}

int main() {
    std::vector<int> arr = {4, 1, 5, 2, 6, 2};
    int k = 3;
    std::cout << "Minimum operations: " << minOperations(arr, k) << std::endl;
    return 0;
}
function minOperations(arr, k) {
    const n = arr.length;
    let totalOperations = 0;
    for (let start = 0; start < k; start++) {
        const dp = [];
        for (let i = start; i < n; i += k) {
            const pos = binarySearch(dp, arr[i]);
            if (pos < dp.length)
                dp[pos] = arr[i];
            else
                dp.push(arr[i]);
        }
        const seqLength = Math.floor((n - start - 1) / k) + 1;
        totalOperations += seqLength - dp.length;
    }
    return totalOperations;
}

function binarySearch(dp, target) {
    let low = 0, high = dp.length;
    while (low < high) {
        const mid = Math.floor((low + high) / 2);
        if (dp[mid] <= target) low = mid + 1;
        else high = mid;
    }
    return low;
}

const arr = [4, 1, 5, 2, 6, 2];
const k = 3;
console.log(`Minimum operations: ${minOperations(arr, k)}`);
#include <stdio.h>
#include <stdlib.h>

int minOperations(int* arr, int n, int k) {
    int* dp = (int*)malloc(n * sizeof(int));
    int totalOperations = 0;
    for (int start = 0; start < k; start++) {
        int len = 0;
        for (int i = start; i < n; i += k) {
            int left = 0, right = len;
            while (left < right) {
                int mid = left + (right - left) / 2;
                if (dp[mid] <= arr[i]) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
            dp[left] = arr[i];
            if (left == len) len++;
        }
        int seqLength = (n - start - 1) / k + 1;
        totalOperations += seqLength - len;
    }
    free(dp);
    return totalOperations;
}

int main() {
    int arr[] = {4, 1, 5, 2, 6, 2};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 2;
    printf("Minimum operations: %d", minOperations(arr, n, k));
    return 0;
}
using System;
using System.Collections.Generic;

class KIncreasing {
    public static int MinOperations(int[] arr, int k) {
        int n = arr.Length;
        int totalOperations = 0;
        for (int start = 0; start < k; start++) {
            List<int> dp = new List<int>();
            for (int i = start; i < n; i += k) {
                int pos = dp.BinarySearch(arr[i]);
                if (pos < 0) pos = ~pos;
                if (pos < dp.Count)
                    dp[pos] = arr[i];
                else
                    dp.Add(arr[i]);
            }
            int seqLength = (n - start - 1) / k + 1;
            totalOperations += seqLength - dp.Count;
        }
        return totalOperations;
    }

    public static void Main(string[] args) {
        int[] arr = { 4, 1, 5, 2, 6, 2 };
        int k = 2;
        Console.WriteLine("Minimum operations: " + MinOperations(arr, k));
    }
}

In Python, the bisect_right function is used to facilitate binary search when determining the position of each element in the current LIS subsequence.

Complexity

Time Complexity: O(n log n/k)
Space Complexity: O(n)

Try this approach in the editor

Approach 2: Default Approach

func kIncreasing(arr []int, k int) int {
	searchRight := func(arr []int, x int) int {
		left, right := 0, len(arr)
		for left < right {
			mid := (left + right) >> 1
			if arr[mid] > x {
				right = mid
			} else {
				left = mid + 1
			}
		}
		return left
	}

	lis := func(arr []int) int {
		var t []int
		for _, x := range arr {
			idx := searchRight(t, x)
			if idx == len(t) {
				t = append(t, x)
			} else {
				t[idx] = x
			}
		}
		return len(arr) - len(t)
	}

	n := len(arr)
	ans := 0
	for i := 0; i < k; i++ {
		var t []int
		for j := i; j < n; j += k {
			t = append(t, arr[j])
		}
		ans += lis(t)
	}
	return ans
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Divide and Solve Subproblems Using LIS

Time Complexity: O(n log n/k)
Space Complexity: O(n)

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
DP Longest Non-Decreasing Subsequence per subsequenceO(n²)O(n)Good for understanding the subsequence transformation or when constraints are small
Divide into K groups + LIS with Binary SearchO(n log n)O(n)Optimal solution for large inputs; typical interview expectation

Frequently asked questions

Is Minimum Operations to Make the Array K-Increasing easy or hard?

Minimum Operations to Make the Array K-Increasing is categorized as a Hard problem. The difficulty comes from recognizing that the constraint splits the array into k independent chains and that minimizing modifications reduces to computing the longest non-decreasing subsequence efficiently.

Minimum Operations to Make the Array K-Increasing Python/Java solution

Implement the solution by iterating through each starting index from 0 to k-1, building the subsequence arr[i], arr[i+k], arr[i+2k], and computing its longest non-decreasing subsequence using binary search. The same logic works in Python, Java, C++, JavaScript, and C# using built-in binary search utilities or manual implementations.

How to solve Minimum Operations to Make the Array K-Increasing in O(n log n)?

Group elements by index modulo k so that each subsequence contains indices i, i+k, i+2k. For each subsequence, compute the longest non-decreasing subsequence using the patience sorting technique with binary search (upper bound). The minimum operations equal the subsequence length minus the LNDS length.

What is the best approach for Minimum Operations to Make the Array K-Increasing?

The optimal approach splits the array into k independent subsequences using indices i, i+k, i+2k. Each subsequence must be non-decreasing. Compute the longest non-decreasing subsequence (LNDS) for each group using a binary-search-based LIS technique and sum m - LNDS for each subsequence. This runs in O(n log n) time.

Is Minimum Operations to Make the Array K-Increasing asked at Google/Amazon/Meta?

Variants of subsequence optimization and LIS-based problems frequently appear in interviews at companies like Google, Amazon, and Meta. This problem specifically tests recognition of LIS patterns combined with array partitioning by index spacing.

What data structure is used in Minimum Operations to Make the Array K-Increasing?

The optimized solution uses arrays (or lists) to store subsequences and a dynamic tails array for the LIS computation. Binary search is applied on the tails array to maintain the smallest possible ending values for subsequences of different lengths.

What is the time complexity of Minimum Operations to Make the Array K-Increasing?

The optimal solution runs in O(n log n) time. Each of the k subsequences is processed using a longest non-decreasing subsequence algorithm implemented with binary search, which takes O(m log m) for subsequence length m. Total space complexity is O(n).

Comments

Now write it yourselfClose this page and solve Minimum Operations to Make the Array K-Increasing in the editor, without looking.
Practise Minimum Operations to Make the Array K-Increasing