题目链接,描述
https://www.lintcode.com/problem/998
java
给定两个数组 arr1 和 arr2, 它们的长度都是 n. arr1 中的元素互不相同.
现在你需要构造 arr1 的另一个排列. 在这个排列中, 数字 arr1[i] 前面有 arr2[i] 个数比它小.
1≤n≤10的5次方
样例
样例 1:
输入:
n = 5,
arr1 = [1, 2, 3, 4 ,5],
arr2 = [0, 0, 0, 1, 3]
输出: [3, 4, 2, 5, 1]
解释:
在 [3, 4, 2, 5, 1] 中, 在 1 之前没有比它自己还小的元素, 2 和 3 也是如此.
在 4 前面有一个 3 比它小.
在 5 前面有 3, 4 和 2 比它小.
样例 2:
输入:
n = 4,
arr1 = [1, 3, 7, 6],
arr2 = [0, 1, 3, 2]
输出: [1, 3, 6, 7]
解释:
1 前面没有元素.
3 前面有一个 1 比它小.
7 前面的 3 个元素都比它小.
6 前面有 1 和 3 比它小.
思路
前置知识:线段树;
本题是比较难的
解题步骤:
先将所有点按从大到小的顺序排列,然后从最大的开始插入到线段树中。
对于区间[l,mid],[mid+1,r]。满足[l,mid]中未被填充的数字比比它自身小的数的个数大,
则继续搜索左区间,反之搜索右区间。填充,更新即可。 时间复杂度为O(nlogn)O(nlogn)。
答案
java
public class Solution {
/**
* @param n: The array sum
* @param arr1: The size
* @param arr2: How many numbers smaller than itself
* @return: The correct array
*/
public int[] getQueue(int n, int[] arr1, int[] arr2) {
/*
先将所有点按从大到小的顺序排列,然后从最大的开始插入到线段树中。
对于区间[l,mid],[mid+1,r]。满足[l,mid]中未被填充的数字比比它自身小的数的个数大,
则继续搜索左区间,反之搜索右区间。填充,更新即可。 时间复杂度为O(nlogn)O(nlogn)。
*/
Info[] arr = new Info[100000+10];
for (int i = 0; i < n; i++) {
arr[i] = new Info(arr1[i],arr2[i]);
}
Arrays.sort(arr,0,n, new Comparator<Info>() {
@Override
public int compare(Info a, Info b) {
return b.data-a.data;
}
});
int[] ans = new int[n];
Node root = build(1,n);
for (int i = 0; i <n ; i++) {
int pos = query(root,arr[i].cnt+1);
ans[pos-1]= arr[i].data;
}
return ans;
}
static class Info{
int data;//值
int cnt; //有几个值比自己小
public Info(int d ,int c){
data =d;
cnt =c;
}
}
static class Node{
int start,end,sum;
Node left,right;
public Node(int s,int e){
start = s;
end=e;
sum =0;
left = null;
right =null;
}
}
public static Node build(int start,int end){
if(start >end) return null;
if(start ==end){
Node nn = new Node(start,end);
nn.sum =1;
return nn;
}
Node root = new Node(start,end);
int m = start+(end-start)/2;
root.left = build(start,m);
root.right = build(m+1,end);
root.sum =0;
if(root.left!=null)
root.sum+= root.left.sum;
if(root.right!=null)
root.sum+=root.right.sum;
return root;
}
public static int query(Node root,int k){
if(root.start > root.end) return 0;
if(root.start == root.end){
root.sum =0;
return root.start;
}
int ans =0;
if(k<=root.left.sum){
ans = query(root.left,k);
}else{
ans = query(root.right,k-root.left.sum);
}
root.sum =0;
if(root.left!=null)
root.sum+= root.left.sum;
if(root.right!=null)
root.sum += root.right.sum;
return ans;
}
}