algorithm - 找到最佳阵列交点

标签 algorithm

我有一个数组数组和一个匹配数组。每个数组都有唯一的 id 值。

匹配数组 = [1,2,3,4,5,6]

A1 = [1, 4, 6]

A2 = [2,3,5]

A3 = [1,5]

A4 = [4]

A5 = [1, 6]

需要找到“最佳匹配”。最佳匹配是 A1-A5 中具有最小长度的子集数组,它应该与 MatchingArray 有最大可能的交集。

对于此示例,有 2 种可能的匹配具有最大交集:M1 = [[2,3,5], [1, 4, 6]] 和 M2 = [[1,5], [4], [ 1, 6]]。但是 M1.length < M2.length,所以算法应该输出 M1。

最佳答案

您可以使用集合(或散列,无论语言如何调用它们)来优化时间效率。

将目标数组转换为集合,然后从中减去选定的源(即删除公共(public)值)。递归地继续这样做,直到目标集为空。跟踪最佳结果(尽可能使用最少的源阵列)。如果正在使用的源数组的数量超过当时已找到的最佳解决方案的长度,则回溯。

这是 Python 中的代码:

def find_optimal_coverage(target, sources):
    max_size = len(target)
    best = None

    def recurse(target, sources, selected):
        nonlocal max_size, best
        if len(target) == 0:
            best = selected
            max_size = len(best) - 1
            return True
        if len(selected) == max_size:
            return None
        for i, source in enumerate(sources):
            result = recurse(target - set(source), sources[i+1:], 
                             selected + [list(source)])
            if result:
                return True

    target = set(target) # convert to set for faster lookup
    # limit the source lists to elements that occur in the target
    sources = list(map(target.intersection, sources))
    # limit target to elements that occur in at least one source
    target = set.union(*sources)
    # sort sources by decreasing length to maximise probability of 
    # finding optimal solution sooner
    sources.sort(key = len, reverse = True)
    if recurse(target, sources, []):
        return best

result = find_optimal_coverage(
    [1, 2, 3, 4, 5, 6, 8], 
    [
        [1, 4, 6, 7],
        [2, 3, 5],
        [1, 5],
        [4],
        [1, 6]
    ]
)
print(result)

查看它在 repl.it 上运行

在 JavaScript 中:

function subtractArray(s, arr) {
    return arr.reduce( (s, v) => (s.delete(v), s), new Set(s) );
}

function findOptimalCoverage(target, sources) {
    var maxSize = target.size;
    var best = null;
    
    function recurse(target, sources, selected) {
        if (target.size == 0) {
            best = selected;
            maxSize = best.length - 1;
            return true;
        }
        if (selected.length == maxSize) return;
        return sources.some( (source, i) =>
            recurse(subtractArray(target, source), sources.slice(i+1), 
                    selected.concat([source]))
        );
    }
    target = new Set(target) // convert to set for faster lookup
    // limit the source arrays to elements that occur in the target
    sources = sources.map( source => source.filter(target.has.bind(target)));
    // limit target to elements that occur in at least one source
    target = new Set([].concat(...sources)); 
    // sort sources by decreasing length to maximise probability of 
    // finding optimal solution sooner
    sources.sort( (a,b) => b.length - a.length );
    if (recurse(target, sources, [])) return best;
}

var result = findOptimalCoverage(
    [1, 2, 3, 4, 5, 6, 8], 
    [
        [1, 4, 6, 7],
        [2, 3, 5],
        [1, 5],
        [4],
        [1, 6]
    ]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

关于algorithm - 找到最佳阵列交点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43428874/

相关文章:

algorithm - 在使用 A* 时实现快捷方式(reach)修剪

algorithm - 使用动态规划的 8 皇后问题

algorithm - 选择算法中的 good pivot VS "bad pivot"有什么区别?

javascript - 展平阵列有哪些实际应用?

c++ - 当我尝试提交 mkbudget spoj 时得到 WA

algorithm - 核密度估计 julia

python - 邻居和新年聚会

algorithm - 随机划分一个二维复封闭区域

c# - 找到基于两个输入的唯一输出?

c# - 计算为 BinarySearch 进行的比较次数