📌  相关文章
📜  从给定的反转数组生成原始排列

📅  最后修改于: 2021-05-17 05:19:02             🧑  作者: Mango

给定大小为N的数组arr [] ,其中arr [i]表示左侧元素的数量大于原始置换中的i元素。任务是找到[1,N]的原始排列,对于该排列,给定的反转数组arr []保持有效。

例子:

天真的方法:最简单的方法是生成N个数的所有排列,对于每个排列,检查其元素是否满足数组arr []给出的反转。如果找到这样的排列,请打印出来。

时间复杂度: O(N!)
辅助空间: O(N)

高效方法:为了优化上述方法,其思想是使用段树。请按照以下步骤解决问题:

  1. 构建一个大小为N的段树,并初始化所有值为1的叶子节点。
  2. 从右到左遍历给定的数组。例如,如果当前索引为N – 1 ,即没有元素被访问。因此, arr [i]是应大于必须在此位置的元素的元素数量。因此,该元素的答案是分段树中(N – arr [N – 1])元素对应于该元素。之后,将该元素标记为0,以避免再次计数。
  3. 类似地,对于从(N – 1)0的每个i ,在段树中找到第(i + 1 – arr [i])元素。
  4. 找到arr [i]的答案后,将其设为temp ,将其存储在ans []数组中,并将索引temp的节点更新为0
  5. 最后,以相反的顺序将答案数组ans []打印为原始排列。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
using namespace std;
const int MAXX = 100;
 
// Declaring segment tree
int st[4 * MAXX];
 
// Function to initialize segment tree
// with leaves filled with ones
void build(int x, int lx, int rx)
{
    // Base Case
    if (rx - lx == 1) {
        st[x] = 1;
        return;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Build the left subtree
    build(x * 2 + 1, lx, m);
 
    // Build the right subtree
    build(x * 2 + 2, m, rx);
 
    // Combining both left and right
    // subtree to parent node
    st[x] = st[x * 2 + 1]
            + st[x * 2 + 2];
 
    return;
}
 
// Function to make index x to 0
// and then update segment tree
void update(int i, int x,
            int lx, int rx)
{
    // Base Case
    if (rx - lx == 1) {
        st[x] = 0;
        return;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Update Query
    if (i < m)
        update(i, x * 2 + 1, lx, m);
    else
        update(i, x * 2 + 2, m, rx);
 
    // Combining both left and right
    // subtree to parent node
    st[x] = st[x * 2 + 1]
            + st[x * 2 + 2];
 
    return;
}
 
// Function to find the Kth element
int getans(int x, int lx, int rx,
           int k, int n)
{
    // Base Condtiion
    if (rx - lx == 1) {
        if (st[x] == k)
            return lx;
        return n;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Check if kth one is in left subtree
    // or right subtree of current node
    if (st[x * 2 + 1] >= k)
        return getans(x * 2 + 1,
                      lx, m, k, n);
    else
        return getans(x * 2 + 2, m,
                      rx, k - st[x * 2 + 1],
                      n);
}
 
// Function to generate the original
// permutation
void getPermutation(int inv[], int n)
{
    // Build segment tree
    build(0, 0, n);
 
    // Stores the original permutation
    vector ans;
 
    for (int i = n - 1; i >= 0; i--) {
 
        // Find kth one
        int temp = getans(0, 0, n,
                          st[0] - inv[i], n);
 
        // Answer for arr[i]
        ans.push_back(temp + 1);
 
        // Setting found value back to 0
        update(max(0, temp), 0, 0, n);
    }
 
    // Print the permutation
    for (int i = n - 1; i >= 0; i--)
        cout << ans[i] << " ";
 
    return;
}
 
// Driver Code
int main()
{
    // Given array
    int inv[] = { 0, 1, 1, 0, 3 };
 
    // Length of the given array
    int N = sizeof(inv) / sizeof(inv[0]);
 
    // Function Call
    getPermutation(inv, N);
 
    return 0;
}


Java
// Java program for the above approach
import java.util.*;
 
class GFG{
  
static int MAXX = 100;
 
// Declaring segment tree
static int []st = new int[4 * MAXX];
 
// Function to initialize segment tree
// with leaves filled with ones
static void build(int x, int lx, int rx)
{
     
    // Base Case
    if (rx - lx == 1)
    {
        st[x] = 1;
        return;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Build the left subtree
    build(x * 2 + 1, lx, m);
 
    // Build the right subtree
    build(x * 2 + 2, m, rx);
 
    // Combining both left and right
    // subtree to parent node
    st[x] = st[x * 2 + 1] + st[x * 2 + 2];
 
    return;
}
 
// Function to make index x to 0
// and then update segment tree
static void update(int i, int x,
                   int lx, int rx)
{
     
    // Base Case
    if (rx - lx == 1)
    {
        st[x] = 0;
        return;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Update Query
    if (i < m)
        update(i, x * 2 + 1, lx, m);
    else
        update(i, x * 2 + 2, m, rx);
 
    // Combining both left and right
    // subtree to parent node
    st[x] = st[x * 2 + 1] + st[x * 2 + 2];
 
    return;
}
 
// Function to find the Kth element
static int getans(int x, int lx, int rx,
                  int k, int n)
{
     
    // Base Condtiion
    if (rx - lx == 1)
    {
        if (st[x] == k)
            return lx;
             
        return n;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Check if kth one is in left subtree
    // or right subtree of current node
    if (st[x * 2 + 1] >= k)
        return getans(x * 2 + 1,
                      lx, m, k, n);
    else
        return getans(x * 2 + 2, m, rx,
               k - st[x * 2 + 1], n);
}
 
// Function to generate the original
// permutation
static void getPermutation(int inv[], int n)
{
     
    // Build segment tree
    build(0, 0, n);
 
    // Stores the original permutation
    Vector ans = new Vector();
 
    for(int i = n - 1; i >= 0; i--)
    {
         
        // Find kth one
        int temp = getans(0, 0, n,
                          st[0] - inv[i], n);
 
        // Answer for arr[i]
        ans.add(temp + 1);
 
        // Setting found value back to 0
        update(Math.max(0, temp), 0, 0, n);
    }
 
    // Print the permutation
    for(int i = n - 1; i >= 0; i--)
        System.out.print(ans.get(i) + " ");
 
    return;
}
 
// Driver Code
public static void main(String args[])
{
     
    // Given array
    int inv[] = { 0, 1, 1, 0, 3 };
 
    // Length of the given array
    int N = inv.length;
 
    // Function Call
    getPermutation(inv, N);
}
}
 
// This code is contributed by SURENDRA_GANGWAR


Python3
# Python3 program for the above approach
MAXX = 100
 
# Declaring segment tree
st = [0] * (4 * MAXX)
 
# Function to initialize segment tree
# with leaves filled with ones
def build(x, lx, rx):
     
    # Base Case
    if (rx - lx == 1):
        st[x] = 1
        return
 
    # Split into two halves
    m = (lx + rx) // 2
 
    # Build the left subtree
    build(x * 2 + 1, lx, m)
 
    # Build the right subtree
    build(x * 2 + 2, m, rx)
 
    # Combining both left and right
    # subtree to parent node
    st[x] = st[x * 2 + 1] + st[x * 2 + 2]
 
    return
 
# Function to make index x to 0
# and then update segment tree
def update(i, x, lx, rx):
     
    # Base Case
    if (rx - lx == 1):
        st[x] = 0
        return
 
    # Split into two halves
    m = (lx + rx) // 2
 
    # Update Query
    if (i < m):
        update(i, x * 2 + 1, lx, m)
    else:
        update(i, x * 2 + 2, m, rx)
 
    # Combining both left and right
    # subtree to parent node
    st[x] = st[x * 2 + 1] + st[x * 2 + 2]
 
    return
 
# Function to find the Kth element
def getans(x, lx, rx, k, n):
     
    # Base Condtiion
    if (rx - lx == 1):
        if (st[x] == k):
            return lx
             
        return n
 
    # Split into two halves
    m = (lx + rx) // 2
 
    # Check if kth one is in left subtree
    # or right subtree of current node
    if (st[x * 2 + 1] >= k):
        return getans(x * 2 + 1, lx, m, k, n)
    else:
        return getans(x * 2 + 2, m, rx,
               k - st[x * 2 + 1], n)
 
# Function to generate the original
# permutation
def getPermutation(inv, n):
     
    # Build segment tree
    build(0, 0, n)
 
    # Stores the original permutation
    ans = []
 
    for i in range(n - 1, -1, -1):
         
        # Find kth one
        temp = getans(0, 0, n, st[0] - inv[i], n)
 
        # Answer for arr[i]
        ans.append(temp + 1)
 
        # Setting found value back to 0
        update(max(0, temp), 0, 0, n)
 
    # Print the permutation
    for i in range(n - 1, -1, -1):
        print(ans[i], end = " ")
 
    return
 
# Driver Code
if __name__ == '__main__':
     
    # Given array
    inv = [ 0, 1, 1, 0, 3 ]
 
    # Length of the given array
    N = len(inv)
 
    # Function Call
    getPermutation(inv, N)
 
# This code is contributed by mohit kumar 29


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
  
static int MAXX = 100;
 
// Declaring segment tree
static int []st = new int[4 * MAXX];
 
// Function to initialize segment tree
// with leaves filled with ones
static void build(int x, int lx, int rx)
{
     
    // Base Case
    if (rx - lx == 1)
    {
        st[x] = 1;
        return;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Build the left subtree
    build(x * 2 + 1, lx, m);
 
    // Build the right subtree
    build(x * 2 + 2, m, rx);
 
    // Combining both left and right
    // subtree to parent node
    st[x] = st[x * 2 + 1] + st[x * 2 + 2];
 
    return;
}
 
// Function to make index x to 0
// and then update segment tree
static void update(int i, int x,
                   int lx, int rx)
{
     
    // Base Case
    if (rx - lx == 1)
    {
        st[x] = 0;
        return;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Update Query
    if (i < m)
        update(i, x * 2 + 1, lx, m);
    else
        update(i, x * 2 + 2, m, rx);
 
    // Combining both left and right
    // subtree to parent node
    st[x] = st[x * 2 + 1] + st[x * 2 + 2];
 
    return;
}
 
// Function to find the Kth element
static int getans(int x, int lx, int rx,
                  int k, int n)
{
     
    // Base Condtiion
    if (rx - lx == 1)
    {
        if (st[x] == k)
            return lx;
             
        return n;
    }
 
    // Split into two halves
    int m = (lx + rx) / 2;
 
    // Check if kth one is in left subtree
    // or right subtree of current node
    if (st[x * 2 + 1] >= k)
        return getans(x * 2 + 1,
                      lx, m, k, n);
    else
        return getans(x * 2 + 2, m, rx,
               k - st[x * 2 + 1], n);
}
 
// Function to generate the original
// permutation
static void getPermutation(int []inv, int n)
{
     
    // Build segment tree
    build(0, 0, n);
 
    // Stores the original permutation
    List ans = new List();
 
    for(int i = n - 1; i >= 0; i--)
    {
         
        // Find kth one
        int temp = getans(0, 0, n,
                          st[0] - inv[i], n);
 
        // Answer for arr[i]
        ans.Add(temp + 1);
 
        // Setting found value back to 0
        update(Math.Max(0, temp), 0, 0, n);
    }
 
    // Print the permutation
    for(int i = n - 1; i >= 0; i--)
        Console.Write(ans[i] + " ");
 
    return;
}
 
// Driver Code
public static void Main(String []args)
{
     
    // Given array
    int []inv = { 0, 1, 1, 0, 3 };
 
    // Length of the given array
    int N = inv.Length;
 
    // Function Call
    getPermutation(inv, N);
}
}
 
// This code is contributed by Amit Katiyar


输出:
4 1 3 5 2








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