用任何正整数进行最小替换以使数组 K 递增
给定一个由N个正整数组成的数组arr[]和一个整数K ,任务是用任何正整数替换最小数量的元素,使数组 K 递增。如果对于范围[K, N)中的每个索引i , arr[i] ≥ arr[iK] ,则数组是K 递增的
例子:
Input: arr[] = {4, 1, 5, 2, 6, 2}, k = 2
Output: 0
Explanation: Here, for every index i where 2 <= i <= 5, arr[i-2] <= arr[i]
Since the given array is already K-increasing, there is no need to perform any operations.
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].
方法:此解决方案基于找到最长的递增子序列。由于上述问题要求arr[iK] ≤ arr[i]对于每个索引i都应成立,其中K ≤ i ≤ N-1,因此这里重要的是比较彼此相距K个位置的元素。
因此,任务是确认由 K 个位置以外的元素形成的序列本质上都是非递减的。如果它们不是,则执行替换以使它们不减少。
请按照以下步骤操作:
- 通过在给定数组中选择彼此远离的K个元素来遍历数组并形成序列( seq[] )。
- 检查seq[]中的所有元素是否不递减。
- 如果不是,则找到 seq[] 的最长非递减子序列的长度。
- 替换其余元素以最小化操作总数。
- 所有此类序列的替换操作之和是最终答案。
请按照下图更好地理解。
• For example: arr[] = {4, 1, 5, 2, 6, 0, 1} ,K = 2
Indices: 0 1 2 3 4 5 6
values: 4 1 5 2 6 0 1
So the work is to ensure that following sequences
- arr[0], arr[2], arr[4], arr[6] => {4, 5, 6, 1}
- arr[1], arr[3], arr[5] => {1, 2, 0}
Obey arr[i-k] <= arr[i]
So for first sequence it can be seen that {4, 5, 6} are K increasing and it is the longest non-decreasing subsequence, whereas 1 is not, so one operation is needed for it.
Similarly, for 2nd {1, 2} are longest non-decreasing whereas 0 is not, so one operation is needed for it.
So total 2 minimum operations are required.
下面是上述方法的实现。
C++
// C++ code to implement above approach
#include
using namespace std;
// Functions finds the
// longest non decreasing subsequence.
int utility(vector& arr, int& n)
{
vector tail;
int len = 1;
tail.push_back(arr[0]);
for (int i = 1; i < n; i++) {
if (tail[len - 1] <= arr[i]) {
len++;
tail.push_back(arr[i]);
}
else {
auto it = upper_bound(tail.begin(),
tail.end(),
arr[i]);
*it = arr[i];
}
}
return len;
}
// Function to find the minimum operations
// to make array K-increasing
int kIncreasing(vector& a, int K)
{
int ans = 0;
// Size of array
int N = a.size();
for (int i = 0; i < K; i++)
{
// Consider all elements K-places away
// as a sequence
vector v;
for (int j = i; j < N; j += K)
{
v.push_back(a[j]);
}
// Size of each sequence
int k = v.size();
// Store least operations
// for this sequence
ans += k - utility(v, k);
}
return ans;
}
// Driver code
int main()
{
vector arr{ 4, 1, 5, 2, 6, 0, 1 };
int K = 2;
cout << kIncreasing(arr, K);
return 0;
}
Python3
# Python code for the above approach
def lowerBound(a, low, high, element):
while (low < high):
middle = low + (high - low) // 2;
if (element > a[middle]):
low = middle + 1;
else:
high = middle;
return low;
def utility(v):
if (len(v) == 0): # boundary case
return 0;
tail = [0] * len(v)
length = 1; # always points empty slot in tail
tail[0] = v[0];
for i in range(1, len(v)):
if (v[i] > tail[length - 1]):
# v[i] extends the largest subsequence
length += 1
tail[length] = v[i];
else:
# v[i] will extend a subsequence and
# discard older subsequence
# find the largest value just smaller than
# v[i] in tail
# to find that value do binary search for
# the v[i] in the range from begin to 0 +
# length
idx = lowerBound(v, 1, len(v), v[i]);
# binarySearch in C# returns negative
# value if searched element is not found in
# array
# this negative value stores the
# appropriate place where the element is
# supposed to be stored
if (idx < 0):
idx = -1 * idx - 1;
# replacing the existing subsequence with
# new end value
tail[idx] = v[i];
return length;
# Function to find the minimum operations
# to make array K-increasing
def kIncreasing(a, K):
ans = 0;
# Size of array
N = len(a)
for i in range(K):
# Consider all elements K-places away
# as a sequence
v = [];
for j in range(i, N, K):
v.append(a[j]);
# Size of each sequence
k = len(v);
# Store least operations
# for this sequence
ans += k - utility(v);
return ans;
# Driver code
arr = [4, 1, 5, 2, 6, 0, 1];
K = 2;
print(kIncreasing(arr, K));
# This code is contributed by gfgking
C#
// C# code for the above approach
using System;
using System.Collections.Generic;
class GFG {
static int lowerBound(List a, int low, int high,
int element)
{
while (low < high) {
int middle = low + (high - low) / 2;
if (element > a[middle])
low = middle + 1;
else
high = middle;
}
return low;
}
static int utility(List v, int n)
{
if (v.Count == 0) // boundary case
return 0;
int[] tail = new int[v.Count];
int length = 1; // always points empty slot in tail
tail[0] = v[0];
for (int i = 1; i < v.Count; i++) {
if (v[i] > tail[length - 1]) {
// v[i] extends the largest subsequence
tail[length++] = v[i];
}
else {
// v[i] will extend a subsequence and
// discard older subsequence
// find the largest value just smaller than
// v[i] in tail
// to find that value do binary search for
// the v[i] in the range from begin to 0 +
// length
var idx = lowerBound(v, 1, v.Count, v[i]);
// binarySearch in C# returns negative
// value if searched element is not found in
// array
// this negative value stores the
// appropriate place where the element is
// supposed to be stored
if (idx < 0)
idx = -1 * idx - 1;
// replacing the existing subsequence with
// new end value
tail[idx] = v[i];
}
}
return length;
}
// Function to find the minimum operations
// to make array K-increasing
static int kIncreasing(int[] a, int K)
{
int ans = 0;
// Size of array
int N = a.Length;
for (int i = 0; i < K; i++)
{
// Consider all elements K-places away
// as a sequence
List v = new List();
for (int j = i; j < N; j += K) {
v.Add(a[j]);
}
// Size of each sequence
int k = v.Count;
// Store least operations
// for this sequence
ans += k - utility(v, k);
}
return ans;
}
// Driver code
public static void Main()
{
int[] arr = { 4, 1, 5, 2, 6, 0, 1 };
int K = 2;
Console.Write(kIncreasing(arr, K));
}
}
// This code is contributed by ukasp.
Javascript
2
时间复杂度: O(K * N * logN)
辅助空间: O(N)