📜  计算递增的子序列数:O(NlogN)

📅  最后修改于: 2021-05-04 18:43:22             🧑  作者: Mango

给定长度为N的数组arr [] ,任务是查找给定数组中严格增加的子序列数。

例子:

方法:本文已经讨论了O(N 2 )方法。在此,将讨论使用段树数据结构的O(NlogN)时间的方法。

在上一篇文章中,使用的递归关系为:

由于每个状态都需要迭代整个子数组arr [i + 1…n-1],因此要花费额外的O(N)时间来解决它。因此,复杂度为(N 2 )。

这样做的目的是避免为每个状态重复O(N)额外循环,并将其复杂度降低为Log(N)。

假设:从每个索引“ i”(其中i大于数字“ k”)开始严格增加的子序列数是已知的。

使用以上假设,可以在log(N)时间中找到从索引“ k”开始的递增子序列数。

因此,必须找到大于“ k”的所有索引“ i”的总和。但是捕获量是arr [i]必须大于arr [k]。要解决该问题,可以执行以下操作:

  1. 对于数组的每个元素,如果对数组进行了排序,则会找到其索引。示例– {7,8,1,9,9,4}在这里,排名将是:
  2. 创建长度为“ N”的段树以回答范围和查询。
  3. 要在求解索引“ k”时回答查询,首先要找到arr [k]的等级。假设等级为R。然后,在段树中,找到从索引{R到N-1}的范围和。
  4. 然后,当segment-(R-1)等于1 + segtree-query(R,N-1)+ segtree-query(R-1,R-1)时,对segment-tree进行点更新。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
  
#define N 10000
  
// Segment tree array
int seg[3 * N];
  
// Function for point update in segment tree
int update(int in, int l, int r, int up_in, int val)
{
    // Base case
    if (r < up_in || l > up_in)
        return seg[in];
  
    // If l==r==up
    if (l == up_in and r == up_in)
        return seg[in] = val;
  
    // Mid element
    int m = (l + r) / 2;
  
    // Updating the segment tree
    return seg[in] = update(2 * in + 1, l, m, up_in, val)
                     + update(2 * in + 2, m + 1, r, up_in, val);
}
  
// Function for the range sum-query
int query(int in, int l, int r, int l1, int r1)
{
    // Base case
    if (l > r)
        return 0;
    if (r < l1 || l > r1)
        return 0;
    if (l1 <= l and r <= r1)
        return seg[in];
  
    // Mid element
    int m = (l + r) / 2;
  
    // Calling for the left and the right subtree
    return query(2 * in + 1, l, m, l1, r1)
           + query(2 * in + 2, m + 1, r, l1, r1);
}
  
// Function to return the count
int findCnt(int* arr, int n)
{
    // Copying array arr to sort it
    int brr[n];
    for (int i = 0; i < n; i++)
        brr[i] = arr[i];
  
    // Sorting array brr
    sort(brr, brr + n);
  
    // Map to store the rank of each element
    map r;
    for (int i = 0; i < n; i++)
        r[brr[i]] = i + 1;
  
    // dp array
    int dp[n] = { 0 };
  
    // To store the final answer
    int ans = 0;
  
    // Updating the dp array
    for (int i = n - 1; i >= 0; i--) {
  
        // Rank of the element
        int rank = r[arr[i]];
  
        // Solving the dp-states using segment tree
        dp[i] = 1 + query(0, 0, n - 1, rank, n - 1);
  
        // Updating the final answer
        ans += dp[i];
  
        // Updating the segment tree
        update(0, 0, n - 1, rank - 1,
               dp[i] + query(0, 0, n - 1, rank - 1, rank - 1));
    }
  
    // Returning the final answer
    return ans;
}
  
// Driver code
int main()
{
    int arr[] = { 1, 2, 10, 9 };
    int n = sizeof(arr) / sizeof(int);
  
    cout << findCnt(arr, n);
  
    return 0;
}


Java
// Java implementation of the approach
import java.util.*;
  
class GFG
{
  
    static final int N = 10000;
  
    // Segment tree array
    static int[] seg = new int[3 * N];
  
    // Function for point update in segment tree
    static int update(int in, int l, int r, int up_in, int val)
    {
        // Base case
        if (r < up_in || l > up_in)
            return seg[in];
  
        // If l==r==up
        if (l == up_in && r == up_in)
            return seg[in] = val;
  
        // Mid element
        int m = (l + r) / 2;
  
        // Updating the segment tree
        return seg[in] = update(2 * in + 1, l, m, up_in, val) +
                update(2 * in + 2, m + 1, r, up_in, val);
    }
  
    // Function for the range sum-query
    static int query(int in, int l, int r, int l1, int r1) 
    {
        // Base case
        if (l > r)
            return 0;
        if (r < l1 || l > r1)
            return 0;
        if (l1 <= l && r <= r1)
            return seg[in];
  
        // Mid element
        int m = (l + r) / 2;
  
        // Calling for the left and the right subtree
        return query(2 * in + 1, l, m, l1, r1) +
                query(2 * in + 2, m + 1, r, l1, r1);
    }
  
    // Function to return the count
    static int findCnt(int[] arr, int n) 
    {
        // Copying array arr to sort it
        int[] brr = new int[n];
        for (int i = 0; i < n; i++)
            brr[i] = arr[i];
  
        // Sorting array brr
        Arrays.sort(brr);
  
        // Map to store the rank of each element
        HashMap r = new HashMap();
        for (int i = 0; i < n; i++)
            r.put(brr[i], i + 1);
  
        // dp array
        int dp[] = new int[n];
  
        // To store the final answer
        int ans = 0;
  
        // Updating the dp array
        for (int i = n - 1; i >= 0; i--)
        {
  
            // Rank of the element
            int rank = r.get(arr[i]);
  
            // Solving the dp-states using segment tree
            dp[i] = 1 + query(0, 0, n - 1, rank, n - 1);
  
            // Updating the final answer
            ans += dp[i];
  
            // Updating the segment tree
            update(0, 0, n - 1, rank - 1, dp[i] +
                    query(0, 0, n - 1, rank - 1, rank - 1));
        }
  
        // Returning the final answer
        return ans;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { 1, 2, 10, 9 };
        int n = arr.length;
  
        System.out.print(findCnt(arr, n));
  
    }
}
  
// This code is contributed by PrinciRaj1992


Python3
# Python3 implementation of the approach
  
N = 10000
  
# Segment tree array
seg = [0] * (3 * N)
  
# Function for point update in segment tree
def update(In, l, r, up_In, val):
      
    # Base case
    if (r < up_In or l > up_In):
        return seg[In]
  
    # If l==r==up
    if (l == up_In and r == up_In):
        seg[In] = val
        return val
  
    # Mid element
    m = (l + r) // 2
  
    # Updating the segment tree
    seg[In] = update(2 * In + 1, l, m, up_In, val) + update(2 * In + 2, m + 1, r, up_In, val)
    return seg[In]
  
  
# Function for the range sum-query
def query(In, l, r, l1, r1):
  
    # Base case
    if (l > r):
        return 0
    if (r < l1 or l > r1):
        return 0
    if (l1 <= l and r <= r1):
        return seg[In]
  
    # Mid element
    m = (l + r) // 2
  
    # CallIng for the left and the right subtree
    return query(2 * In + 1, l, m, l1, r1)+ query(2 * In + 2, m + 1, r, l1, r1)
  
  
# Function to return the count
def fIndCnt(arr, n):
  
    # Copying array arr to sort it
    brr = [0] * n
    for i in range(n):
        brr[i] = arr[i]
  
    # Sorting array brr
    brr = sorted(brr)
  
    # Map to store the rank of each element
    r = dict()
    for i in range(n):
        r[brr[i]] = i + 1
  
    # dp array
    dp = [0] * n
  
    # To store the final answer
    ans = 0
  
    # Updating the dp array
    for i in range(n - 1, -1, -1):
  
        # Rank of the element
        rank = r[arr[i]]
  
        # Solving the dp-states using segment tree
        dp[i] = 1 + query(0, 0, n - 1, rank, n - 1)
  
        # UpdatIng the final answer
        ans += dp[i]
  
        # Updating the segment tree
        update(0, 0, n - 1, rank - 1,dp[i] + query(0, 0, n - 1, rank - 1, rank - 1))
  
    # Returning the final answer
    return ans
  
# Driver code
  
arr = [1, 2, 10, 9]
n = len(arr)
  
print(fIndCnt(arr, n))
  
# This code is contributed by mohit kumar 29


C#
// C# implementation of the approach
using System;
using System.Collections.Generic;
  
class GFG
{
  
    static readonly int N = 10000;
  
    // Segment tree array
    static int[] seg = new int[3 * N];
  
    // Function for point update In segment tree
    static int update(int In, int l, int r, 
                        int up_in, int val)
    {
        // Base case
        if (r < up_in || l > up_in)
            return seg[In];
  
        // If l==r==up
        if (l == up_in && r == up_in)
            return seg[In] = val;
  
        // Mid element
        int m = (l + r) / 2;
  
        // Updating the segment tree
        return seg[In] = update(2 * In + 1, l, m, up_in, val) +
                update(2 * In + 2, m + 1, r, up_in, val);
    }
  
    // Function for the range sum-query
    static int query(int In, int l, int r, int l1, int r1) 
    {
        // Base case
        if (l > r)
            return 0;
        if (r < l1 || l > r1)
            return 0;
        if (l1 <= l && r <= r1)
            return seg[In];
  
        // Mid element
        int m = (l + r) / 2;
  
        // Calling for the left and the right subtree
        return query(2 * In + 1, l, m, l1, r1) +
                query(2 * In + 2, m + 1, r, l1, r1);
    }
  
    // Function to return the count
    static int findCnt(int[] arr, int n) 
    {
        // Copying array arr to sort it
        int[] brr = new int[n];
        for (int i = 0; i < n; i++)
            brr[i] = arr[i];
  
        // Sorting array brr
        Array.Sort(brr);
  
        // Map to store the rank of each element
        Dictionary r = new Dictionary();
        for (int i = 0; i < n; i++)
            r.Add(brr[i], i + 1);
  
        // dp array
        int []dp = new int[n];
  
        // To store the readonly answer
        int ans = 0;
  
        // Updating the dp array
        for (int i = n - 1; i >= 0; i--)
        {
  
            // Rank of the element
            int rank = r[arr[i]];
  
            // Solving the dp-states using segment tree
            dp[i] = 1 + query(0, 0, n - 1, rank, n - 1);
  
            // Updating the readonly answer
            ans += dp[i];
  
            // Updating the segment tree
            update(0, 0, n - 1, rank - 1, dp[i] +
                    query(0, 0, n - 1, rank - 1, rank - 1));
        }
  
        // Returning the readonly answer
        return ans;
    }
  
    // Driver code
    public static void Main(String[] args)
    {
        int []arr = { 1, 2, 10, 9 };
        int n = arr.Length;
  
        Console.Write(findCnt(arr, n));
  
    }
}
  
// This code is contributed by PrinciRaj1992


输出:
11