给定大小为N的数组arr [] ,其中arr [i]表示左侧元素的数量大于原始置换中的第i个元素。任务是找到[1,N]的原始排列,对于该排列,给定的反转数组arr []保持有效。
例子:
Input: arr[] = {0, 1, 1, 0, 3}
Output: 4 1 3 5 2
Explanation:
The original permutation is ans[] = {4, 1, 3, 5, 2}
ans[0] = 4.
ans[1] = 1. Since {4} exists on its left, which exceeds 1, arr[1] = 1 holds valid.
ans[2] = 3. Since {4} exists on its left, which exceeds 3, arr[2] = 1 holds valid.
ans[3] = 5. Since no elements on its left exceeds 5, arr[3] = 0 holds valid.
ans[4] = 2. Since {4, 3, 5} exists on its left, which exceeds 2, arr[4] = 3 holds valid.
Input: arr[] = {0, 1, 2}
Output: 3 2 1
天真的方法:最简单的方法是生成N个数的所有排列,对于每个排列,检查其元素是否满足数组arr []给出的反转。如果找到这样的排列,请打印出来。
时间复杂度: O(N!)
辅助空间: O(N)
高效方法:为了优化上述方法,其思想是使用段树。请按照以下步骤解决问题:
- 构建一个大小为N的段树,并初始化所有值为1的叶子节点。
- 从右到左遍历给定的数组。例如,如果当前索引为N – 1 ,即没有元素被访问。因此, arr [i]是应大于必须在此位置的元素的元素数量。因此,该元素的答案是分段树中第(N – arr [N – 1])个元素对应于该元素。之后,将该元素标记为0,以避免再次计数。
- 类似地,对于从(N – 1)到0的每个i ,在段树中找到第(i + 1 – arr [i])个元素。
- 找到arr [i]的答案后,将其设为temp ,将其存储在ans []数组中,并将索引temp的节点更新为0 。
- 最后,以相反的顺序将答案数组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)