给定一个数字数组和一个常数k,请使用以下删除元素的规则将数组的大小最小化。
- 可以一次删除3个元素。
- 删除的三个元素必须在数组中相邻,即arr [i],arr [i + 1],arr [i + 2]。并且第二个元素必须比第一个元素大k,第三个元素必须比第二个元素大k,即arr [i + 1] – arr [i] = k和arr [i + 2] -arr [i + 1] = k。
例子:
Input: arr[] = {2, 3, 4, 5, 6, 4}, k = 1
Output: 0
We can actually remove all elements.
First remove 4, 5, 6 => We get {2, 3, 4}
Now remove 2, 3, 4 => We get empty array {}
Input: arr[] = {2, 3, 4, 7, 6, 4}, k = 1
Output: 3
We can only remove 2 3 4
来源:https://code.google.com/codejam/contest/4214486/dashboard#s=p2
强烈建议您最小化浏览器,然后自己尝试。
对于每个元素arr [i],都有两种可能性
1)要么不删除该元素。
2)删除OR元素(如果遵循删除规则)。删除元素后,又有两种可能性。
…..a)可以直接将其删除,即,初始arr [i + 1]为arr [i] + k,而arr [i + 2]为arr [i] + 2 * k。
…..b)存在x和y,使得arr [x] – arr [i] = k,arr [y] – arr [x] = k,以及子数组“ arr [i + 1…x-1]” &“ arr [x + 1…y-1]”可以完全删除。
下面是基于以上思想的递归算法。
// Returns size of minimum possible size of arr[low..high]
// after removing elements according to given rules
findMinSize(arr[], low, high, k)
// If there are less than 3 elements in arr[low..high]
1) If high-low+1 < 3, return high-low+1
// Consider the case when 'arr[low]' is not considered as
// part of any triplet to be removed. Initialize result
// using this case
2) result = 1 + findMinSize(arr, low+1, high)
// Case when 'arr[low]' is part of some triplet and removed
// Try all possible triplets that have arr[low]
3) For all i from low+1 to high
For all j from i+1 to high
Update result if all of the following conditions are met
a) arr[i] - arr[low] = k
b) arr[j] - arr[i] = k
c) findMinSize(arr, low+1, i-1, k) returns 0
d) findMinSize(arr, i+1, j-1, k) also returns 0
e) Result calculated for this triplet (low, i, j)
is smaller than existing result.
4) Return result
上述解决方案的时间复杂度是指数的。如果绘制完整的递归树,则可以观察到许多子问题一次又一次地得到解决。由于再次调用了相同的问题,因此此问题具有“重叠子问题”属性。像其他典型的动态编程(DP)问题一样,可以通过构造临时数组dp [] []来存储子问题的结果,从而避免相同子问题的重新计算。以下是基于动态编程的解决方案
以下是上述想法的实现。该实现是基于记忆的,即,它是递归的,并使用查找表dp [] []来检查子问题是否已解决。
C++
// C++ program to find size of minimum possible array after
// removing elements according to given rules
#include
using namespace std;
#define MAX 1000
// dp[i][j] denotes the minimum number of elements left in
// the subarray arr[i..j].
int dp[MAX][MAX];
int minSizeRec(int arr[], int low, int high, int k)
{
// If already evaluated
if (dp[low][high] != -1)
return dp[low][high];
// If size of array is less than 3
if ( (high-low + 1) < 3)
return high-low +1;
// Initialize result as the case when first element is
// separated (not removed using given rules)
int res = 1 + minSizeRec(arr, low+1, high, k);
// Now consider all cases when first element forms a triplet
// and removed. Check for all possible triplets (low, i, j)
for (int i = low+1; i<=high-1; i++)
{
for (int j = i+1; j <= high; j++ )
{
// Check if this triplet follows the given rules of
// removal. And elements between 'low' and 'i' , and
// between 'i' and 'j' can be recursively removed.
if (arr[i] == (arr[low] + k) &&
arr[j] == (arr[low] + 2*k) &&
minSizeRec(arr, low+1, i-1, k) == 0 &&
minSizeRec(arr, i+1, j-1, k) == 0)
{
res = min(res, minSizeRec(arr, j+1, high, k));
}
}
}
// Insert value in table and return result
return (dp[low][high] = res);
}
// This function mainlu initializes dp table and calls
// recursive function minSizeRec
int minSize(int arr[], int n, int k)
{
memset(dp, -1, sizeof(dp));
return minSizeRec(arr, 0, n-1, k);
}
// Driver prrogram to test above function
int main()
{
int arr[] = {2, 3, 4, 5, 6, 4};
int n = sizeof(arr)/sizeof(arr[0]);
int k = 1;
cout << minSize(arr, n, k) << endl;
return 0;
}
Java
// Java program to find size of
// minimum possible array after
// removing elements according
// to given rules
class GFG
{
static int MAX = 1000;
// dp[i][j] denotes the minimum
// number of elements left in
// the subarray arr[i..j].
static int dp[][] = new int[MAX][MAX];
static int minSizeRec(int arr[], int low,
int high, int k)
{
// If already evaluated
if (dp[low][high] != -1)
{
return dp[low][high];
}
// If size of array is less than 3
if ((high - low + 1) < 3)
{
return high - low + 1;
}
// Initialize result as the
// case when first element is
// separated (not removed
// using given rules)
int res = 1 + minSizeRec(arr,
low + 1, high, k);
// Now consider all cases when
// first element forms a triplet
// and removed. Check for all
// possible triplets (low, i, j)
for (int i = low + 1; i <= high - 1; i++)
{
for (int j = i + 1; j <= high; j++)
{
// Check if this triplet
// follows the given rules of
// removal. And elements
// between 'low' and 'i' , and
// between 'i' and 'j' can
// be recursively removed.
if (arr[i] == (arr[low] + k) &&
arr[j] == (arr[low] + 2 * k) &&
minSizeRec(arr, low + 1, i - 1, k) == 0 &&
minSizeRec(arr, i + 1, j - 1, k) == 0)
{
res = Math.min(res, minSizeRec(arr, j + 1, high, k));
}
}
}
// Insert value in table and return result
return (dp[low][high] = res);
}
// This function mainlu initializes
// dp table and calls recursive
// function minSizeRec
static int minSize(int arr[], int n, int k)
{
for (int i = 0; i < MAX; i++)
{
for (int j = 0; j < MAX; j++)
{
dp[i][j] = -1;
}
}
return minSizeRec(arr, 0, n - 1, k);
}
// Driver code
public static void main(String[] args)
{
int arr[] = {2, 3, 4, 5, 6, 4};
int n = arr.length;
int k = 1;
System.out.println(minSize(arr, n, k));
}
}
// This code is contributed by 29AjayKumar
Python3
# Python3 program to find size of
# minimum possible array after
# removing elements according to given rules
MAX=1000
dp=[[-1 for i in range(MAX)] for i in range(MAX)]
# dp[i][j] denotes the minimum number of elements left in
# the subarray arr[i..j].
def minSizeRec(arr,low,high,k):
# If already evaluated
if dp[low][high] != -1:
return dp[low][high]
# If size of array is less than 3
if (high-low + 1) < 3:
return (high-low + 1)
# Initialize result as the case when first element is
# separated (not removed using given rules)
res = 1 + minSizeRec(arr, low+1, high, k)
# Now consider all cases when
# first element forms a triplet
# and removed. Check for all possible
# triplets (low, i, j)
for i in range(low+1,high):
for j in range(i+1,high+1):
# Check if this triplet follows the given rules of
# removal. And elements between 'low' and 'i' , and
# between 'i' and 'j' can be recursively removed.
if (arr[i]==(arr[low]+k) and arr[j] == (arr[low] + 2*k) and
minSizeRec(arr, low+1, i-1, k) == 0 and
minSizeRec(arr, i+1, j-1, k) == 0):
res=min(res,minSizeRec(arr,j+1,high,k) )
# Insert value in table and return result
dp[low][high] = res
return res
# This function mainly initializes dp table and calls
# recursive function minSizeRec
def minSize(arr,n,k):
dp=[[-1 for i in range(MAX)] for i in range(MAX)]
return minSizeRec(arr, 0, n-1, k)
# Driver program to test above function
if __name__=='__main__':
arr=[2, 3, 4, 5, 6, 4]
n=len(arr)
k=1
print(minSize(arr,n,k))
# this code is contributed by sahilshelangia
C#
// C# program to find size of
// minimum possible array after
// removing elements according
// to given rules
using System;
class GFG
{
static int MAX = 1000;
// dp[i,j] denotes the minimum
// number of elements left in
// the subarray arr[i..j].
static int [,]dp = new int[MAX, MAX];
static int minSizeRec(int []arr, int low,
int high, int k)
{
// If already evaluated
if (dp[low, high] != -1)
{
return dp[low, high];
}
// If size of array is less than 3
if ((high - low + 1) < 3)
{
return high - low + 1;
}
// Initialize result as the
// case when first element is
// separated (not removed
// using given rules)
int res = 1 + minSizeRec(arr,
low + 1, high, k);
// Now consider all cases when
// first element forms a triplet
// and removed. Check for all
// possible triplets (low, i, j)
for (int i = low + 1; i <= high - 1; i++)
{
for (int j = i + 1; j <= high; j++)
{
// Check if this triplet
// follows the given rules of
// removal. And elements
// between 'low' and 'i' , and
// between 'i' and 'j' can
// be recursively removed.
if (arr[i] == (arr[low] + k) &&
arr[j] == (arr[low] + 2 * k) &&
minSizeRec(arr, low + 1, i - 1, k) == 0 &&
minSizeRec(arr, i + 1, j - 1, k) == 0)
{
res = Math.Min(res, minSizeRec(arr, j + 1, high, k));
}
}
}
// Insert value in table and return result
return (dp[low, high] = res);
}
// This function mainlu initializes
// dp table and calls recursive
// function minSizeRec
static int minSize(int []arr, int n, int k)
{
for (int i = 0; i < MAX; i++)
{
for (int j = 0; j < MAX; j++)
{
dp[i, j] = -1;
}
}
return minSizeRec(arr, 0, n - 1, k);
}
// Driver code
public static void Main(String[] args)
{
int []arr = {2, 3, 4, 5, 6, 4};
int n = arr.Length;
int k = 1;
Console.WriteLine(minSize(arr, n, k));
}
}
// This code contributed by Rajput-Ji
输出:
0