找到最佳阵列交叉点

时间:2017-04-15 17:08:04

标签: algorithm

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

MatchingArray = [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的最大可能交点。

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

2 个答案:

答案 0 :(得分:1)

在javascript中实现算法:

var matchingArray = [1, 2, 3, 4, 5, 6];

var A1 = [1, 4, 6],
  A2 = [2, 3, 5],
  A3 = [1, 5],
  A4 = [4],
  A5 = [1, 6];


var M = [A1, A2, A3, A4, A5];

function compareArrays(M, machingArray) {
  var intersections = []
  M.forEach(function(A) {
    var partOfItersections;
    if (A.length > 0) {
      var intersectionsCount = getIntersectionCount(A, machingArray);
      partOfItersections = intersectionsCount / A.length;
    } else {
      partOfItersections = 0
    }

    intersections.push({
      length: A.length,
      partOfItersections: partOfItersections
    });
  });


  //alert(JSON.stringify(intersections));

  var maxLength = 0,
    maxPartOfItersections = 0,
    optimalArrays = [];

  intersections.forEach(function(arrayData, index) {
    var currentArr = M[index];
    var currentArrLength = currentArr.length;
    if (maxPartOfItersections < arrayData.partOfItersections) {

      setCurrentOptimalArr(arrayData.partOfItersections, currentArr);
    } else if (maxPartOfItersections === arrayData.partOfItersections) {
      if (maxLength < currentArrLength) {
        setCurrentOptimalArr(arrayData.partOfItersections, currentArr);
      } else if (maxLength === currentArrLength) {
        optimalArrays.push(currentArr);
      }
    }
  });

  //alert(JSON.stringify(optimalArrays));

  return optimalArrays;

  function setCurrentOptimalArr(intersectionsCount, currentArr) {
    optimalArrays = [currentArr];
    maxLength = currentArr.length;
    maxPartOfItersections = intersectionsCount;
  }

  function getIntersectionCount(A, machingArray) {
    var intersectionCount = 0;

    A.forEach(function(elem) {
      if (machingArray.indexOf(elem) != -1) {
        intersectionCount++;
      }
    });


    return intersectionCount;
  }
}

alert(JSON.stringify(compareArrays(M, matchingArray)));

  1. 分别计算数组的交集。
  2. 返回包含更多部分交叉点的数组。
  3. 代码已更新

答案 1 :(得分:1)

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

将目标数组转换为集合,然后从中减去所选源(即删除常用值)。继续以递归方式执行此操作,直到目标集为空。跟踪最佳结果(尽可能使用最少的源阵列)。如果正在使用的源数组的数量超过当时已找到的最佳解决方案的长度,则回溯。

以下是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中:

&#13;
&#13;
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);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;