给定大小为A
的数组N
我需要计算此类三元组(i
,j
,k
),以便:
Condition 1 : i < j < k
Condition 2 : A[i] > A[j] > A[k]
我知道一个O(N^3)
解决方案。他们可以使用O(N)
或O(NlogN)
解决方案来解决此问题,因为N
最多可以100000
示例:让N=4
和数组为[4,3,2,1]
,然后回答为{4,3,2}
,{4,3,1}
,{4,2,1}
和{ {1}}都是可能的答案
如何为给定的{3,2,1}
和数组N
找到此计数?
我的方法:
A
答案 0 :(得分:3)
首先,对数组进行排序,维护每个元素的索引。
class Node{
int index, val;
}
为了比较两个节点,我们首先需要比较它们的值。如果值等于,我们将比较它们的索引,如果其索引更小,则认为节点更大。
现在,按排序顺序处理每个节点,我们尝试将每个节点的索引添加到Fenwick tree。因此,对于每个索引i
,我们在树中查询此索引的频率,该索引先前已添加到树中。这是值大于当前索引值的索引数。
注意对于case元素具有相等的值,通过上面提到的排序机制,我们将首先添加那些具有更大索引的树,因此,不会影响频率值查询从树上。
应用类似步骤以获取小于i
且索引为j < i
的元素。
例如:
如果我们有一个数组
{0(1) ,1(2) , 2(2) ,3(4) , 4(4) ,5(4) ,6(1)} //index(value)
After sort -> {5(4), 4(4), 3(4), 2(2), 1(2), 6(1), 0(1) }
伪代码
Node[]data;
sort(data)
Fenwick tree;
int[]less;
int[]more;
for(int i = 0; i < data.length; i++){
less[data[i].index] = tree.query(data[i].index);
tree.add(data[i].index, 1);
}
tree.clear();
for(int i = data.length - 1; i >= 0; i--){
more[data[i].index] = tree.query(data.length) -tree.query(data[i].index);
tree.add(data[i].index, 1);
}
int result = 0;
for(int i = 0; i < data.length; i++)
result += more[i]*less[i];
时间复杂度为O(n logn)。
使用Java代码(FT是我的Fenwick树)
PrintWriter out;
Scanner in = new Scanner(System.in);
out = new PrintWriter(System.out);
int n = in.nextInt();
Node[] data = new Node[n];
for (int i = 0; i < n; i++) {
data[i] = new Node(i + 1, in.nextInt());
}
FT tree = new FT(n + 2);
Arrays.sort(data, new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
if (o1.val != o2.val) {
return o2.val - o1.val;
}
return o2.index - o1.index;
}
});
int[] less = new int[n];//Store all nodes with greater index and smaller value;
int[] greater = new int[n];//Store all nodes with smaller index and greater value
for (int i = 0; i < n; i++) {
greater[data[i].index - 1] = (int) tree.get(data[i].index);
tree.update(data[i].index, 1);
}
tree = new FT(n + 2);
for (int i = n - 1; i >= 0; i--) {
less[data[i].index - 1] = (int) (tree.get(n) - tree.get(data[i].index));
tree.update(data[i].index, 1);
}
long total = 0;
for (int i = 0; i < n; i++) {
total += less[i] * greater[i];
}
out.println(total);
out.close();
答案 1 :(得分:1)
你可以很容易地在 O(n * n)中做到这一点,你只需要跟踪每个元素有多少个小数:
vector<int> smallerNumbers(A.size());
for (int i = A.size() - 2; i >= 0; --i){
for (int j = i + 1; j < A.size(); ++j){
if (A[i] > A[j]){
smallerNumbers[i]++;
count += smallerNumbers[j];
}
}
}
对于 O(nklogn)解决方案,请在此处查看我的回答:https://stackoverflow.com/a/28379003/2642059
请注意,这是针对递增序列的,并且您要求递减序列。
要实现这一目标,您需要撤消mapIndex
创建的排名。因此,在创建temp
之前,只需将mapIndex
替换为partial_sort_copy
,然后转换 partial_sort_copy(values.cbegin(), values.cend(), temp.rbegin(), temp.rend());
:
{{1}}