在一个维度中找到最短路径

时间:2011-04-13 13:44:45

标签: algorithm

在一维数组S中,可能存在属于集合

的任意数量的元素
U:{A,B,C,D,E}  

允许重复 示例:

S  = {E,B,D,C,A,D,A,E,E,D,B,B,A,C} 

问题是:

在任何给定的数组S中,我能够确定包含属于集合U的所有元素的最短范围/路径的最有效方法是什么?请记住,数组无法排序。

在上面的例子中,最短的路径是连接数组S的前5个元素。

编辑:
1)集合U的元素数不是常数。

提前致谢。

5 个答案:

答案 0 :(得分:2)

有趣的家庭作业,但你仍然需要自己编码。

好的是你没有告诉我们你使用哪种语言,所以我把它作为一个标志,因为你决定自己编码,这很好。


到目前为止我最好的尝试:

有2个指针用于子字符串(范围),一个用于范围的 start (较小的索引),另一个用于 end (较大的索引)。两者都先指向数组的开头。

列出分别有多少 ABCDE。

从左到右迭代结束

对于每个字符,请增加列表中字符的数字。如果结果(递增多少)> 1(,看看 start 是否指向同一个字符。如果是,请将开始向前移动减1,然后) start 指向a字符相关的数字> 1,向前移动开始,然后向下移动。

如果列表中的ABCDE都是> = 1,那么我们就找到了候选范围。将其与最短长度(如果有)进行比较,如果它更小,则更新最短长度并记录新最短范围的 start 的索引。

答案 1 :(得分:1)

如果我正确理解问题,我认为你需要这样做(语言不可知)

int partLen <- U.length;
do {
    Vector subSets <- S.partition(partLen);
    foreach set I in subSets
        if I.isEqualTo(U) then
            return true;
        else
            partLen <- partLen + 1;
} while (partLen <= S.length);
return false;

partition将S分解为任何长度的子集 isEqualTo可以正确比较集合。

答案 2 :(得分:1)

这是一个简单的算法,它扫描阵列一次,不断检查它当前看到的覆盖范围是否比之前看到的覆盖范围短。

为简单起见,我假设我们可以将A,B,C,D和E映射到整数0-4,这样我们就可以轻松地引用一个数组。我没有彻底检查过,所以请在心理上/实际上运行一两个示例以确保它能够满足您的需求。

//Cell 0 is the last index at which we saw an A, cell 1 " " saw a B, etc.
int[] mostRecent = new int[U.length];
mostRecent.setAllValsTo(POSITIVE_INFINITY);

int shortestRange = POSITIVE_INFINITY; //We are trying to minimize this number.
int minIndex = 0; //The beginning index of the range
int maxIndex = POSITIVE_INFINITY; //The ending index of the range.

for(int i=0; i< S.length; i++) {
    int currentValue = S[i]; //This value will be 0-4, corresponding to A-E

    mostRecent[currentValue] = i;

    currentMax = mostRecent.findMax(); //beginning of current range
    currentMin = mostRecent.findMin(); //end of current range
    currentRange = currentMax - currentMin;

    if(currentRange < shortestRange) {
        shortestRange = currentRage;
        minIndex = currentMin;
        maxIndex = currentMax;
    }
}

//currentMax and currentMin now carry the starting and ending indices, use them as you see fit.
return shortestRange;

这是阶数O(nk),其中n = S.length且k = U.length。仍然有很多优化可以挤出来,但我不知道是否可以降低最坏情况下的订单。

答案 3 :(得分:1)

首先在数组中找到不同的元素,即O(n)个东西。然后使用滑动窗口方法找到所有这些元素都存在的最小跨度。

您可以看到here如何找到最小窗口:http://tech-queries.blogspot.com/2010/12/finding-minimum-window-in-array-which.html

答案 4 :(得分:0)

以下是我将如何做到这一点(伪代码)

let counters[] be an array such that 
counters[j] = number of occurrences of character j, 
where j = 0 for 'A', j = 1 for 'B', etc.

build counters[] by scanning the original string s

let positions[j][] be an array listing the positions occupied by 
character j in the original string s; note the size of 
positions[j][] is equal to counters[j]

build positions[j][] by scanning the original string s;

let currentPositions[] be an array such that 
positions[j][currentPositions[j]] gives the position of the next 
occurrence of character j in the original string s

initially currentPositions[j] = 0 for every j = [0 .. u.length]

let bestLength = s.length
let bestMin = 0
let bestMax = 0
for i in [0 .. s.length] {
    for j in [0 .. u.length] {
        if ( 
          positions[i][currentPositions[i]] < i and 
          currentPositions[j] + 1 < counters[j]
        )
          currentPositions[j]++
    }
    let min = s.length
    int max = 0
    for j in [0 .. u.length] {
        curPos = positions[j][currentPositions[j]
        if (curPos > max) let max = curPos
        if (curPos < min) let min = curPos
    }
    if (max - min + 1 < bestLength) {
        let bestMin = min
        let bestMax = max
        let bestLength = max - min + 1
    }
}

the shortest path is that starting at bestMin, ending at bestMax, 
and having length bestLength

复杂度为O(nk),其中n = s.length,k = u.length