📜  最长递增子序列(N log N)的构造

📅  最后修改于: 2022-05-13 01:57:49.684000             🧑  作者: Mango

最长递增子序列(N log N)的构造

在我之前的帖子中,我已经详细解释了最长递增子序列(LIS)问题。但是,该帖子仅涉及与查询 LIS 大小相关的代码,而不涉及 LIS 的构建。我把它留作练习。如果你已经解决了,干杯。如果没有,你并不孤单,这里是代码。
如果您还没有阅读我之前的帖子,请阅读此处。请注意,以下代码以相反的顺序打印 LIS。我们可以使用堆栈(显式或系统堆栈)修改打印顺序。我将解释作为练习(简单)。

C++
// C++ implementation to find longest increasing subsequence
// in O(n Log n) time.
#include 
using namespace std;
 
// Binary search
int GetCeilIndex(int arr[], vector& T, int l, int r,
                 int key)
{
    while (r - l > 1) {
        int m = l + (r - l) / 2;
        if (arr[T[m]] >= key)
            r = m;
        else
            l = m;
    }
 
    return r;
}
 
int LongestIncreasingSubsequence(int arr[], int n)
{
    // Add boundary case, when array n is zero
    // Depend on smart pointers
 
    vector tailIndices(n, 0); // Initialized with 0
    vector prevIndices(n, -1); // initialized with -1
 
    int len = 1; // it will always point to empty location
    for (int i = 1; i < n; i++) {
        if (arr[i] < arr[tailIndices[0]]) {
            // new smallest value
            tailIndices[0] = i;
        }
        else if (arr[i] > arr[tailIndices[len - 1]]) {
            // arr[i] wants to extend largest subsequence
            prevIndices[i] = tailIndices[len - 1];
            tailIndices[len++] = i;
        }
        else {
            // arr[i] wants to be a potential condidate of
            // future subsequence
            // It will replace ceil value in tailIndices
            int pos = GetCeilIndex(arr, tailIndices, -1,
                                   len - 1, arr[i]);
 
            prevIndices[i] = tailIndices[pos - 1];
            tailIndices[pos] = i;
        }
    }
 
    cout << "LIS of given input" << endl;
    for (int i = tailIndices[len - 1]; i >= 0; i = prevIndices[i])
        cout << arr[i] << " ";
    cout << endl;
 
    return len;
}
 
int main()
{
    int arr[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    printf("LIS size %d\n", LongestIncreasingSubsequence(arr, n));
 
    return 0;
}


Java
// Java implementation to find longest
// increasing subsequence in O(n Log n)
// time.
import java.util.Arrays;
 
class GFG {
 
    // Binary search
    static int GetCeilIndex(int arr[],
                            int T[], int l,
                            int r, int key)
    {
 
        while (r - l > 1) {
 
            int m = l + (r - l) / 2;
            if (arr[T[m]] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    static int LongestIncreasingSubsequence(
        int arr[], int n)
    {
 
        // Add boundary case, when array n is zero
        // Depend on smart pointers
 
        int tailIndices[] = new int[n];
 
        // Initialized with 0
        Arrays.fill(tailIndices, 0);
 
        int prevIndices[] = new int[n];
 
        // initialized with -1
        Arrays.fill(prevIndices, -1);
 
        // it will always point to empty
        // location
        int len = 1;
 
        for (int i = 1; i < n; i++) {
            if (arr[i] < arr[tailIndices[0]])
 
                // new smallest value
                tailIndices[0] = i;
 
            else if (arr[i] > arr[tailIndices[len - 1]]) {
 
                // arr[i] wants to extend
                // largest subsequence
                prevIndices[i] = tailIndices[len - 1];
                tailIndices[len++] = i;
            }
            else {
 
                // arr[i] wants to be a potential
                // condidate of future subsequence
                // It will replace ceil value in
                // tailIndices
                int pos = GetCeilIndex(arr,
                                       tailIndices, -1, len - 1, arr[i]);
 
                prevIndices[i] = tailIndices[pos - 1];
                tailIndices[pos] = i;
            }
        }
 
        System.out.println("LIS of given input");
 
        for (int i = tailIndices[len - 1]; i >= 0;
             i = prevIndices[i])
            System.out.print(arr[i] + " ");
 
        System.out.println();
 
        return len;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = arr.length;
 
        System.out.print("LIS size\n" + LongestIncreasingSubsequence(arr, n));
    }
}
 
// This code is contributed by Anant Agarwal.


Python3
# Python implementation to
# find longest increasing
# subsequence
# in O(n Log n) time.
 
# Binary search
def GetCeilIndex(arr, T, l, r, key):
 
    while (r - l > 1):
     
        m = l + (r - l)//2
        if (arr[T[m]] >= key):
            r = m
        else:
            l = m
 
    return r
  
def LongestIncreasingSubsequence(arr, n):
 
    # Add boundary case,
    # when array n is zero
    # Depend on smart pointers
     
    # Initialized with 0
    tailIndices =[0 for i in range(n + 1)] 
 
    # Initialized with -1
    prevIndices =[-1 for i in range(n + 1)] 
     
    # it will always point
    # to empty location
    len = 1
    for i in range(1, n):
     
        if (arr[i] < arr[tailIndices[0]]):
         
            # new smallest value
            tailIndices[0] = i
         
        elif (arr[i] > arr[tailIndices[len-1]]):
         
            # arr[i] wants to extend
            # largest subsequence
            prevIndices[i] = tailIndices[len-1]
            tailIndices[len] = i
            len += 1
         
        else:
         
            # arr[i] wants to be a
            # potential condidate of
            # future subsequence
            # It will replace ceil
            # value in tailIndices
            pos = GetCeilIndex(arr, tailIndices, -1,
                                   len-1, arr[i])
  
            prevIndices[i] = tailIndices[pos-1]
            tailIndices[pos] = i
         
    print("LIS of given input")
    i = tailIndices[len-1]
    while(i >= 0):
        print(arr[i], " ", end ="")
        i = prevIndices[i]
    print()
  
    return len
 
# driver code
arr = [ 2, 5, 3, 7, 11, 8, 10, 13, 6 ]
n = len(arr)
  
print("LIS size\n", LongestIncreasingSubsequence(arr, n))
 
# This code is contributed
# by Anant Agarwal.


C#
// C# implementation to find longest
// increasing subsequence in O(n Log n)
// time.
using System;
 
class GFG {
 
    // Binary search
    static int GetCeilIndex(int[] arr, int[] T, int l,
                            int r, int key)
    {
 
        while (r - l > 1) {
            int m = l + (r - l) / 2;
 
            if (arr[T[m]] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    static int LongestIncreasingSubsequence(
        int[] arr, int n)
    {
 
        // Add boundary case, when array n is zero
        // Depend on smart pointers
 
        int[] tailIndices = new int[n];
 
        // Initialized with 0
        for (int i = 0; i < n; i++)
            tailIndices[i] = 0;
 
        int[] prevIndices = new int[n];
 
        // initialized with -1
        for (int i = 0; i < n; i++)
            prevIndices[i] = -1;
 
        // it will always point to empty
        // location
        int len = 1;
 
        for (int i = 1; i < n; i++) {
            if (arr[i] < arr[tailIndices[0]])
 
                // new smallest value
                tailIndices[0] = i;
 
            else if (arr[i] > arr[tailIndices[len - 1]]) {
 
                // arr[i] wants to extend
                // largest subsequence
                prevIndices[i] = tailIndices[len - 1];
                tailIndices[len++] = i;
            }
            else {
 
                // arr[i] wants to be a potential
                // condidate of future subsequence
                // It will replace ceil value in
                // tailIndices
                int pos = GetCeilIndex(arr,
                                       tailIndices, -1, len - 1, arr[i]);
 
                prevIndices[i] = tailIndices[pos - 1];
                tailIndices[pos] = i;
            }
        }
 
        Console.Write("LIS of given input");
 
        for (int i = tailIndices[len - 1]; i >= 0;
             i = prevIndices[i])
            Console.Write(arr[i] + " ");
 
        Console.WriteLine();
 
        return len;
    }
 
    // Driver code
    public static void Main()
    {
        int[] arr = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = arr.Length;
 
        Console.Write("LIS size\n" + LongestIncreasingSubsequence(arr, n));
    }
}
 
// This code is contributed by nitin mittal.


PHP
 1)
    {
        $m = (int)($l + ($r - $l)/2);
        if ($arr[$T[$m]] >= $key)
            $r = $m;
        else
            $l = $m;
    }
 
    return $r;
}
 
function LongestIncreasingSubsequence($arr, $n)
{
    // Add boundary case, when array n is zero
    // Depend on smart pointers
 
    $tailIndices=array_fill(0, $n+1, 0); // Initialized with 0
    $prevIndices=array_fill(0, $n+1, -1); // initialized with -1
 
    $len = 1; // it will always point to empty location
    for ($i = 1; $i < $n; $i++)
    {
        if ($arr[$i] < $arr[$tailIndices[0]])
        {
            // new smallest value
            $tailIndices[0] = $i;
        }
        else if ($arr[$i] > $arr[$tailIndices[$len-1]])
        {
            // arr[i] wants to extend largest subsequence
            $prevIndices[$i] = $tailIndices[$len-1];
            $tailIndices[$len++] = $i;
        }
        else
        {
            // arr[i] wants to be a potential condidate of
            // future subsequence
            // It will replace ceil value in tailIndices
            $pos = GetCeilIndex($arr, $tailIndices, -1,
                                $len-1, $arr[$i]);
 
            $prevIndices[$i] = $tailIndices[$pos-1];
            $tailIndices[$pos] = $i;
        }
    }
 
    echo "LIS of given input\n";
    for ($i = $tailIndices[$len-1]; $i >= 0; $i = $prevIndices[$i])
        echo $arr[$i]." ";
    echo "\n";
 
    return $len;
}
 
// Driver code
$arr = array( 2, 5, 3, 7, 11, 8, 10, 13, 6 );
$n = count($arr);
 
print("LIS size ".LongestIncreasingSubsequence($arr, $n));
 
// This code is contributed by chandan_jnu
?>


Javascript


输出:

LIS of given input
13 10 8 7 3 2 
LIS size 6

时间复杂度:O(N*log(N))