在一维数组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的元素数不是常数。
提前致谢。
答案 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