📌  相关文章
📜  使用给定的删除元素规则查找数组的最小可能大小

📅  最后修改于: 2021-09-17 06:44:55             🧑  作者: Mango

给定一个数字数组和一个常数 k,使用以下删除元素的规则来最小化数组的大小。

  • 一次可以移除正好三个元素。
  • 移除的三个元素必须在数组中相邻,即arr[i]、arr[i+1]、arr[i+2]。并且第二个元素必须比第一个元素大 k,第三个元素必须比第二个元素大 k,即 arr[i+1] – arr[i] = k 和 arr[i+2]-arr[i+1] =克。

例子:

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


Javascript


输出:

0

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程