开发者

Find the shortest path in one dimension

In the one dimensional array S , Th开发者_C百科ere might be any number of elements that belong to the set

U:{A,B,C,D,E}  

and repetition is allowed.

Example :

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

Question is:

What is the most efficient way in which I can determine the shortest range/path that contains all the elements belonging to set U ,In any given array S ? keep in mind the array can't be sorted.

In the above example the shortest path is that connecting the first 5 elements of the array S.

EDIT :

1) The Number Of Elements of set U isn't constant.

Thanks in advance.


Interesting homework, but you still have to code yourself.

Good thing is you have not told us which language you use, so I take it as a sign as you've decided to code yourself, which is good.


My best try so far:

Have 2 pointers for the sub string (range), one for the start (smaller index) of the range and one for the end (larger index). Both point to the beginning of the array first.

Have a list for how many ABCDEs are in the range respectively.

Iterate end from left to right.

For every character, increment the number for the character in the list. If the result (incremented how many) > 1(, see if start points to the same character. If yes, move start forward and minus 1, and) while start points to a character the related number for which > 1, move start forward and minus 1.

If ABCDE in the list all >= 1, then we've found a candidate range. Compare it to the shortest length (if any), and if it is smaller, update the shortest length and record the index for the start of the new shortest range.


If I understand the problem correctly I think you need to do (language agnostic)

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;

Where partition will break up S into subsets of whatever length and isEqualTo can properly compare sets.


First find different elements in the array, which is O(n) stuff. Then use sliding window approach to find minimum span, in which all these elements are present.

You can see here how to find the minimum window: http://tech-queries.blogspot.com/2010/12/finding-minimum-window-in-array-which.html


Here's a simple algorithm which scans the array once, constantly checking if its currently-seen covering range is shorter than the previously seen covering ranges.

For simplicity, I'm going to assume that we can map A, B, C, D, and E to the integers 0-4 so that we can easily reference an array. I haven't checked it thoroughly, so please mentally/actually run it on an example or two to make sure it does what you want.

//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;

This is order O(nk), with n=S.length and k=U.length. There are still plenty of optimizations to squeeze out of it, but I don't know if I could bring the worst-case order lower.


Here is how I would do it (in pseudocode)

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

Complexity is O(nk), where n = s.length and k = u.length

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜