📜  最大长度链对| DP-20

📅  最后修改于: 2021-10-26 06:06:25             🧑  作者: Mango

给你 n 对数字。在每一对中,第一个数字总是小于第二个数字。如果 b < c,一对 (c, d) 可以跟在另一对 (a, b) 之后。可以以这种方式形成对链。找出可以从给定的一组对中形成的最长链。
资料来源:亚马逊专访 | 2套
例如,如果给定的对是 {{5, 24}, {39, 60}, {15, 28}, {27, 40}, {50, 90} },那么可以形成的最长链是长度为 3,链为 {{5, 24}, {27, 40}, {50, 90}}

此问题是标准最长递增子序列问题的变体。以下是一个简单的两步过程。
1)按第一个(或更小的)元素的升序对给定的对进行排序。为什么不需要排序?考虑示例 {{6, 8}, {3, 4}} 以了解排序的需要。如果我们在不排序的情况下进行第二步,我们得到的输出是 1。但正确的输出是 2。
2) 现在运行一个修改后的 LIS 过程,我们将已完成的 LIS 的第二个元素与正在构建的新 LIS 的第一个元素进行比较。
下面的代码是对本文方法2的轻微修改。

C++
// CPP program for above approach
#include 
using namespace std;
 
// Structure for a Pair
class Pair
{
    public:
    int a;
    int b;
};
 
// This function assumes that arr[]
// is sorted in increasing order
// according the first
// (or smaller) values in Pairs.
int maxChainLength( Pair arr[], int n)
{
    int i, j, max = 0;
    int *mcl = new int[sizeof( int ) * n ];
     
    /* Initialize MCL (max chain length)
    values for all indexes */
    for ( i = 0; i < n; i++ )
        mcl[i] = 1;
     
    /* Compute optimized chain
    length values in bottom up manner */
    for ( i = 1; i < n; i++ )
        for ( j = 0; j < i; j++ )
            if ( arr[i].a > arr[j].b &&
                    mcl[i] < mcl[j] + 1)
                mcl[i] = mcl[j] + 1;
     
    // mcl[i] now stores the maximum
    // chain length ending with Pair i
     
    /* Pick maximum of all MCL values */
    for ( i = 0; i < n; i++ )
        if ( max < mcl[i] )
            max = mcl[i];
     
    /* Free memory to avoid memory leak */
     
    return max;
}
     
 
/* Driver code */
int main()
{
    Pair arr[] = { {5, 24}, {15, 25},
                        {27, 40}, {50, 60} };
    int n = sizeof(arr)/sizeof(arr[0]);
    cout << "Length of maximum size chain is "
                  << maxChainLength( arr, n );
    return 0;
}
 
// This code is contributed by rathbhupendra


C
#include
#include
 
// Structure for a pair
struct pair
{
  int a;
  int b;
};
 
// This function assumes that
// arr[] is sorted in increasing order
// according the first
// (or smaller) values in pairs.
int maxChainLength( struct pair arr[], int n)
{
   int i, j, max = 0;
   int *mcl = (int*) malloc ( sizeof( int ) * n );
 
   /* Initialize MCL (max chain
     length) values for all indexes */
   for ( i = 0; i < n; i++ )
      mcl[i] = 1;
 
   /* Compute optimized chain length
   values in bottom up manner */
   for ( i = 1; i < n; i++ )
      for ( j = 0; j < i; j++ )
         if ( arr[i].a > arr[j].b &&
                mcl[i] < mcl[j] + 1)
            mcl[i] = mcl[j] + 1;
 
   // mcl[i] now stores the maximum
   // chain length ending with pair i
   
   /* Pick maximum of all MCL values */
   for ( i = 0; i < n; i++ )
      if ( max < mcl[i] )
         max = mcl[i];
 
   /* Free memory to avoid memory leak */
   free( mcl );
 
   return max;
}
 
 
/* Driver program to test above function */
int main()
{
    struct pair arr[] = { {5, 24}, {15, 25},
                          {27, 40}, {50, 60} };
    int n = sizeof(arr)/sizeof(arr[0]);
    printf("Length of maximum size chain is %d\n",
           maxChainLength( arr, n ));
    return 0;
}


Java
// Java program for above approach
class Pair
{
    int a;
    int b;
     
    public Pair(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
     
    // This function assumes that
    // arr[] is sorted in increasing order
    // according the first (or smaller)
    // values in pairs.
    static int maxChainLength(Pair arr[], int n)
    {
       int i, j, max = 0;
       int mcl[] = new int[n];
      
       /* Initialize MCL (max chain length)
        values for all indexes */
       for ( i = 0; i < n; i++ )
          mcl[i] = 1;
      
       /* Compute optimized chain length
        values in bottom up manner */
       for ( i = 1; i < n; i++ )
          for ( j = 0; j < i; j++ )
             if ( arr[i].a > arr[j].b &&
                    mcl[i] < mcl[j] + 1)
                mcl[i] = mcl[j] + 1;
      
       // mcl[i] now stores the maximum
       // chain length ending with pair i
      
       /* Pick maximum of all MCL values */
       for ( i = 0; i < n; i++ )
          if ( max < mcl[i] )
             max = mcl[i];
      
       return max;
    }
 
    /* Driver program to test above function */
    public static void main(String[] args)
    {
        Pair arr[] = new Pair[]
        {
          new Pair(5,24),
          new Pair(15, 25),                     
          new Pair (27, 40),
          new Pair(50, 60)};
         System.out.println("Length of maximum
                               size chain is " +
                 maxChainLength(arr, arr.length));
    }
}


Python3
# Python program for above approach
class Pair(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
 
# This function assumes
# that arr[] is sorted in increasing
# order according the
# first (or smaller) values in pairs.
def maxChainLength(arr, n):
     
    max = 0
 
    # Initialize MCL(max chain
    # length) values for all indices
    mcl = [1 for i in range(n)]
 
    # Compute optimized chain
    # length values in bottom up manner
    for i in range(1, n):
        for j in range(0, i):
            if (arr[i].a > arr[j].b and
                  mcl[i] < mcl[j] + 1):
                mcl[i] = mcl[j] + 1
 
    # mcl[i] now stores the maximum
    # chain length ending with pair i
 
    # Pick maximum of all MCL values
    for i in range(n):
        if (max < mcl[i]):
            max = mcl[i]
 
    return max
 
# Driver program to test above function
arr = [Pair(5, 24), Pair(15, 25),
       Pair(27, 40), Pair(50, 60)]
 
print('Length of maximum size chain is',
      maxChainLength(arr, len(arr)))
 
# This code is contributed by Soumen Ghosh


C#
// Dynamic C# program to find
// Maximum Length Chain of Pairs
using System;
 
class Pair
{
    int a;
    int b;
     
    public Pair(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
     
    // This function assumes that arr[]
    // is sorted in increasing order
    // according the first (or smaller)
    // values in pairs.
    static int maxChainLength(Pair []arr, int n)
    {
        int i, j, max = 0;
        int []mcl = new int[n];
         
        // Initialize MCL (max chain length)
        // values for all indexes
        for(i = 0; i < n; i++ )
            mcl[i] = 1;
         
        // Compute optimized chain length
        // values in bottom up manner
        for(i = 1; i < n; i++)
            for (j = 0; j < i; j++)
                if(arr[i].a > arr[j].b &&
                   mcl[i] < mcl[j] + 1)
                    
          // mcl[i] now stores the maximum
          // chain length ending with pair i
          mcl[i] = mcl[j] + 1;
 
        // Pick maximum of all MCL values
        for ( i = 0; i < n; i++ )
            if (max < mcl[i] )
                max = mcl[i];
         
        return max;
    }
 
    // Driver Code
    public static void Main()
    {
        Pair []arr = new Pair[]
        {new Pair(5,24), new Pair(15, 25),
        new Pair (27, 40), new Pair(50, 60)};
        Console.Write("Length of maximum size
                                chain is " +
                 maxChainLength(arr, arr.Length));
    }
}
 
// This code is contributed by nitin mittal.


Javascript


CPP14
// CPP program for above approach
#include 
using namespace std;
 
// Structure val
struct val
{
    int first;
    int second;
};
 
map, int> m;
 
// Memoisation function
int findMaxChainLen(struct val p[], int n,
                        int prev, int pos)
{
     
    // Check if pair { pos, prev } exists
    // in m
    if (m.find({ pos, prev }) != m.end())
    {
        return m[{ pos, prev }];
    }
 
    // Check if pos is >=n
    if (pos >= n)
        return 0;
 
    // Check if p[pos].first is
    // less than prev
    if (p[pos].first <= prev)
    {
        return findMaxChainLen(p, n, prev,
                                 pos + 1);
    }
 
    else
    {
        int ans = max(findMaxChainLen(p, n,
                             p[pos].second, 0) + 1,
                      findMaxChainLen(p, n,
                                   prev, pos + 1));
        m[{ pos, prev }] = ans;
        return ans;
    }
}
 
// Function to calculate maximum
// chain length
int maxChainLen(struct val p[], int n)
{
    m.clear();
   
    // Call memoisation function
    int ans = findMaxChainLen(p, n, 0, 0);
    return ans;
}
 
// Driver Code
int main()
{
 
    int n = 5;
    val p[n];
    p[0].first = 5;
    p[0].second = 24;
 
    p[1].first = 39;
    p[1].second = 60;
 
    p[2].first = 15;
    p[2].second = 28;
 
    p[3].first = 27;
    p[3].second = 40;
 
    p[4].first = 50;
    p[4].second = 90;
     
    // Function Call
    cout << maxChainLen(p, n) << endl;
    return 0;
}


输出
Length of maximum size chain is 3

时间复杂度: O(n^2) 其中 n 是对的数量。

给定的问题也是活动选择问题的变体,可以在 (nLogn) 时间内解决。要将其作为活动选择问题来解决,请考虑活动选择问题中的对的第一个元素作为开始时间,将对的第二个元素作为结束时间。

另一种方法(自顶向下动态规划):
现在我们将探索使用动态规划的自顶向下的方法递归+记忆)解决这个问题的方法。
由于我们将使用自顶向下的方法解决上述问题,因此我们的第一步是找出递推关系。获得递推关系的最好和最简单的方法是考虑我们在每个状态或位置上的选择。
如果我们仔细查看上述问题,我们会发现每个位置/索引都存在两个选择。两个选择是:
选择 1:选择特定位置的元素并探索其余元素, (或)
选择 2:将元素留在该位置并探索其余元素。
请注意,只有当该位置的第一个元素大于我们之前选择的第二个元素时,我们才能选择特定位置的元素(这是问题中给出的约束)。因此,在递归中,我们维护一个变量,它会告诉我们我们选择的前一个元素。
此外,我们必须最大化我们的答案。因此,我们必须通过在每个位置探索上述两个选择来找出最大的结果选项。
由此产生的递推关系将是:

T(n) = max( maxlenchain(p,n,p[pos].second,0)+1,maxlenchain(p,n,prev_choosen_ele,pos+1) )
请注意函数签名如下:
int cal(struct val p[],int n,int prev_choosen_ele,int pos);

尽管如此,我们不应该忘记我们在递归中的基本条件。如果没有,我们的代码将通过永远执行而根本不停止来享受假期。
所以,我们这个问题的基本条件非常简单。如果我们到达探索的结尾,我们只返回 0,因为不可能有更多的链。

if(pos >= n) 返回 0;

为了避免重复性任务,我们使用了动态编程魔法(这是一种降低时间复杂度的魔法)。我们将位置和前一个元素存储在地图中。如果我们碰巧使用相同的先前元素来到相同的位置,我们不会再次重新计算。我们只是从地图中返回答案。
下面是上述方法的实现:

CPP14

// CPP program for above approach
#include 
using namespace std;
 
// Structure val
struct val
{
    int first;
    int second;
};
 
map, int> m;
 
// Memoisation function
int findMaxChainLen(struct val p[], int n,
                        int prev, int pos)
{
     
    // Check if pair { pos, prev } exists
    // in m
    if (m.find({ pos, prev }) != m.end())
    {
        return m[{ pos, prev }];
    }
 
    // Check if pos is >=n
    if (pos >= n)
        return 0;
 
    // Check if p[pos].first is
    // less than prev
    if (p[pos].first <= prev)
    {
        return findMaxChainLen(p, n, prev,
                                 pos + 1);
    }
 
    else
    {
        int ans = max(findMaxChainLen(p, n,
                             p[pos].second, 0) + 1,
                      findMaxChainLen(p, n,
                                   prev, pos + 1));
        m[{ pos, prev }] = ans;
        return ans;
    }
}
 
// Function to calculate maximum
// chain length
int maxChainLen(struct val p[], int n)
{
    m.clear();
   
    // Call memoisation function
    int ans = findMaxChainLen(p, n, 0, 0);
    return ans;
}
 
// Driver Code
int main()
{
 
    int n = 5;
    val p[n];
    p[0].first = 5;
    p[0].second = 24;
 
    p[1].first = 39;
    p[1].second = 60;
 
    p[2].first = 15;
    p[2].second = 28;
 
    p[3].first = 27;
    p[3].second = 40;
 
    p[4].first = 50;
    p[4].second = 90;
     
    // Function Call
    cout << maxChainLen(p, n) << endl;
    return 0;
}

输出
3

https://www.youtube.com/watch?v=v

-HIXptqM3Q

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