数组的有序笛卡尔积

4
高效排序的两个有序整数数组的笛卡尔积中,建议使用惰性算法来生成两个有序整数数组的有序笛卡尔积。
我想知道是否有一般化的算法可适用于更多的数组。
例如,我们有5个已排序的双精度数组
(0.7, 0.2, 0.1)
(0.6, 0.3, 0.1)
(0.5, 0.25, 0.25)
(0.4, 0.35, 0.25)
(0.35, 0.35, 0.3)
我希望能够生成有序的笛卡尔积,而无需计算所有可能的组合。
如何将可能的惰性笛卡尔积算法扩展到超过2个维度上?非常感谢任何想法。

假设您有两个n维点:A(A1,...,An)和B(B1,...,Bn)。您如何比较它们?什么时候是A < B? - Lajos Arpad
抱歉没有表达清楚。 - mrod
еҰӮжһңA=0.70.60.50.40.3=0.0252пјҢB=0.70.60.50.350.35=0.025725пјҢеҲҷA<BгҖӮ - mrod
0.70.60.50.40.3和0.70.60.50.350.35的数字来自A和B坐标的哪里?谢谢你的例子,但是我对任务的要求非常严格,以至于我甚至不会尝试去想一下问题是否被100%地说明。 - Lajos Arpad
假设x1=(0.7, 0.2, 0.1)、x2=(0.6, 0.3, 0.1)、x3=(0.5, 0.25, 0.25)、x4=(0.4, 0.35, 0.25)、x5=(0.35, 0.35, 0.3)。则A=x1(0)*x2(0)*x3(0)*x4(0)*x5(2),B=x1(0)*x2(0)*x3(0)*x4(1)*x5(0),其中括号中的数字是从零开始的x数组索引。 - mrod
现在问题已经被理解了。我正在考虑一个解决方案。 - Lajos Arpad
2个回答

2
这个问题似乎是一种统一成本搜索的枚举实例(参见例如https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)。您的状态空间由指向已排序数组的当前索引集定义。后继函数是每个数组可能的索引增量的枚举。对于您给定的5个数组示例,初始状态为(0, 0, 0, 0, 0)。
没有目标状态检查函数,因为我们需要遍历所有可能性。如果所有输入数组都已排序,则结果保证已排序。
假设我们有m个长度为n的数组,则此方法的复杂度为O((n ^ m).log(n(m-1))。
以下是Python的示例实现:
from heapq import heappush, heappop

def cost(s, lists):
    prod = 1
    for ith, x in zip(s, lists):
        prod *= x[ith]
    return prod

def successor(s, lists):
    successors = []
    for k, (i, x) in enumerate(zip(s, lists)):
        if i < len(x) - 1: 
            t = list(s)
            t[k] += 1
            successors.append(tuple(t))
    return successors

def sorted_product(initial_state, lists):    
    fringe = []
    explored = set()
    heappush(fringe, (-cost(initial_state, lists), initial_state))
    while fringe:
        best = heappop(fringe)[1]
        yield best
        for s in successor(best, lists):
            if s not in explored:
                heappush(fringe, (-cost(s, lists), s))
                explored.add(s)

if __name__ == '__main__':
    lists = ((0.7, 0.2, 0.1),
             (0.6, 0.3, 0.1),
             (0.5, 0.25, 0.25),
             (0.4, 0.35, 0.25),
             (0.35, 0.35, 0.3))
    init_state = tuple([0]*len(lists))
    for s in sorted_product(init_state, lists):
        s_output = [x[i] for i, x in zip(s, lists)]
        v = cost(s, lists)
        print '%s %s \t%s' % (s, s_output, cost(s, lists))

谢谢,这对我在Java中解决自然语言问题非常有帮助。 - Sam

0

所以,如果你有A(A1,...,An)和B(B1,...,Bn)。

当且仅当

A1 * ... * An < B1 * ... * Bn时,A < B

我假设每个值都是正数,因为如果我们允许负数,那么:

(-50,-100,1)>(1,2,3)

因为-50 *(-100)* 1 = 5000> 6 = 1 * 2 * 3

即使没有负值,问题仍然相当复杂。您需要一个解决方案,其中包括一个深度为k的数据结构。如果(A1,...,Ak)<(B1,...,Bk),则我们可以假设在其他维度上,(A1,...,Ak,...,An)的组合可能小于(B1,...,Bk,...,Bn)的组合。因此,无论何时这不成立,情况都会打破概率,因此这些将是规则的例外情况。数据结构应包含:

  • k
  • A和B的前k个元素
  • 规则例外的描述
对于任何这样的异常情况,可能存在一个(C1, ..., Ck)的组合大于(B1, ..., Bk),但是更大的(C1, ..., Ck)组合仍然可能使用进一步维度的值组合,其中(A1, ..., Ak) < (C1, ..., Ck)的规则异常仍然存在。
因此,如果您已经知道(A1, ..., Ak) < (B1, ..., Bk),那么首先必须检查是否存在异常,方法是找到第一个l维度,在选择A的最大可能值和B的最小可能值时。如果存在这样的l,则应找到异常开始的位置(哪个维度,哪个索引)。这将描述异常情况。当您发现异常时,您知道(A1, ..., Ak, ..., Al)的组合>(B1, ..., Bk, ..., Bl),因此在这里规则是A比B大,并且当B变得比A大时会出现异常。
为了反映这一点,数据结构应如下所示:
class Rule {
    int k;
    int[] smallerCombinationIndexes;
    int[] biggerCombinationIndexes;
    List<Rule> exceptions;
}

每当你发现一个规则的例外时,这个例外都是基于先前的知识产生的。显然,复杂性大大增加了,问题在于你有规则的例外,还有例外的例外等等。当前的方法会告诉你,如果你取两个随机点 A 和 B,A 是否小于 B,它还会告诉你,如果你取 (A1, ..., Ak) 和 (B1, ..., Bk) 的组合,那么在哪些关键索引处 (A1, ..., Ak) 和 (B1, ..., Bk) 的比较结果会改变。根据你确切的需求,这个想法可能已经足够,或者需要扩展。所以你的问题的答案是:是的,你可以扩展懒惰算法来处理更多的维度,但你需要处理规则的例外才能实现这一点。


感谢@LajosArpad的回复。您的假设是正确的,这些数字始终为正数。 - mrod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接