计算满足给定条件的三胞胎

时间:2015-02-05 13:36:31

标签: c++ algorithm dynamic-programming

给定大小为A的数组N我需要计算此类三元组(ijk),以便:

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

2 个答案:

答案 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}}