最长递增子序列(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))