Algorithm to step over array elements as per the given condition - arrays

I am practicing to solve this problem, and have gotten 5 test cases passed but some test cases are failing I am not able to figure out what's the issue in my algorithm. Although I tried with some test data from failed test cases, most of them are coming correctly but I believe some are incorrect hence leading to my algorithm failure. So If someone can give an insight on the correct way to implement this algorithm that would be very helpful or where am I going wrong in my implementation.
My Algo:
1. Index for the move is at index '0' of string (say moving index)
2. Loop over the string starting with index '1' of string:
2.1. check if (moving index + leap) can outrun the array:
2.2. If not then, check whether the character is 1 or 0 :
2.2.1 Check for the number of '1's that are continuous, if they exceed the leap value then return false (as anyway we will not be able to jump).
2.2.2 If its 0, then check whether its a zero after continuous '1's.
If not so, continue moving forward one step at a time.
If so, first try to skip over those continuous '1's by checking whether (moving index + leap) is allowed or not as per the rule.
If not allowed, check in a while loop till what point we can move backwards one step at a time to get (moving index + leap) to satisfy.
If not possible, return false.
I don't know whether this is an efficient way to implement solution of this sort of problem, any other possible methods are much appreciated.
code:
import java.util.*;
public class Solution {
public static int leapStep(int index,int leap,int len,int[] game){
if(game[index+leap]==0){
index += leap;
}
return index;
}
public static boolean canWin(int leap, int[] game) {
int index = 0;
int len = game.length;
int consecutiveLength=0;
for(int i=1;i<len;){
if(index+leap>len-1){
return true;
}
if(game[i]==1){
consecutiveLength++;
if(consecutiveLength>=leap){
return false;
}
i++;
}else{
if(consecutiveLength==0){
index =i;
i++;
}else{
if(index+leap<=len-1){
int tryLeap = leapStep(index,leap,len,game);
if(index < tryLeap){
index = tryLeap;
tryLeap =0;
i = index+1;
}else if(index>0 && game[index-1]==0 ){
boolean notViable = false;
while(index>0){
if(game[index-1]!=0)
return false;
index -= 1;
i = index+1;
tryLeap = leapStep(index,leap,len,game);
if(index<tryLeap){
index = tryLeap;
i = index+1;
tryLeap=0;
notViable = false;
break;
}
else{
notViable = true;
}
}
if(notViable){
return false;
}
}else{
return false;
}
}
consecutiveLength=0;
}
}
}//closing for
return true;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int q = scan.nextInt();
while (q-- > 0) {
int n = scan.nextInt();
int leap = scan.nextInt();
int[] game = new int[n];
for (int i = 0; i < n; i++) {
game[i] = scan.nextInt();
}
System.out.println( (canWin(leap, game)) ? "YES" : "NO" );
}
scan.close();
}
}

To me, a better approach is to solve this recursively as below (it passed all the tests):
public static boolean canWin(int[] array, int index, int leap) {
// the only case when we lose
if (index < 0 || array[index] > 0) {
return false;
}
// if you're standing in the last entry or (index + leap) >= array.length then win
if ((index >= array.length - 1) || ((index + leap) >= array.length)) {
return true;
}
// mark it as visited so that not to iterate over it again
array[index] = 1;
// check all 3 conditions then recursively again
return canWin(array, index + 1, leap) || canWin(array, index - 1, leap) || canWin(array, index + leap, leap);
}
In the input below several pairs of lines are shown. The first element of each pair stands for leap and the second one for an array.
Input:
3
0 0 0 0 0
5
0 0 0 1 1 1
3
0 0 1 1 1 0
1
0 1 0
Output:
true
true
false
false
Explanation:
Let's say your current position is index.
If it's negative or the array value is larger than 0 then the game is lost. If it's the last position or index + leap reaches at least the length of the array then the game is won by definition.
Otherwise, the only possible moves from here could be index - 1 or index + 1 or index + leap. So, you repeat step 1 for each of the latter indices and take OR of the result because finding a single path is enough. Don't forget to set a value of the cell to 1 because it doesn't make sense to visit it the second time - we don't want to repeat the same moves over and over again and crash.

Your pseudo-code seems fine, but there a few mistake in your code, that may be the cause of your trouble.
The least problematic first, if(index+leap<=len-1) inside your loop is useless, you can remove it without modify the behaviour of your algorithm. It is the case because you already checked it in the first line of the loop and entered an else keyword.
This one is about your variables index and i. Their meaning isn't clear to me after a few complete read, and they look like the same. It might cause you trouble because you use the variable index inside your call to leapStep, but index is often one step behind i. It's confusing.
I did not found an example where your code fails.
Here is my solution HackerRank accepted. It is an iterative one, close to yours. Its principle is simple: starting from position 0, as we increase step by step our position, keep track of the positions you have access to (in variable memoTab, I removed the dp name as it can be frightening): if we are on a position we already reached before, then we can go to +1 or +leap.
It would be enough if it wasn't allowed to backtrack and go the reverse direction. To deal with that, whenever we reach some 1s, I keep in memory the next 0. And if I encounter a position I can reach just after, I go back to that 0 and say I can go there.
Here is the code, first a little helper function that returns true if the game is finished. Given a game and an index it says if we can go to that index and write it to the memo.
public static boolean check(int[] game, boolean[] memo, int index){
if(index >= 0 && index < game.length){
if(game[index] != 1){
memo[index] = true;
}
}
return index >= game.length;
}
This is the solver function, it first reads the values, then starts looping.
public static void solveOne(){
int n = sc.nextInt();
int leap = sc.nextInt();
int[] game = new int[n];
for (int i = 0; i < n; i++) {
game[i] = sc.nextInt();
}
int index = 0;
boolean[] memoTab = new boolean[n];
for (int i = 0; i < n; i++) {
memoTab[i] = false;
}
memoTab[0] = true;
boolean rememberIndex0 = false;
boolean gotoIndex0 = false;
int index0 = 0;
boolean finished = false;
We are done with the initialization, let's loop:
while(index < game.length){
// we encounter the first 0 after some 1, keep it in memory !
if(rememberIndex0 && game[index] == 0){
index0 = index;
gotoIndex0 = true;
rememberIndex0 = false;
}
// this index is an index we reached before, we can continue from here
if(memoTab[index]){
// we previously said we need to go back to a lower position
if(gotoIndex0){
gotoIndex0 = false;
index = index0;
memoTab[index] = true;
continue;
}
// it's finished if either is true
finished = check(game, memoTab, index + 1)
|| check(game, memoTab, index + leap);
if(finished) break;
}
// if this position is a 1, then we will keep in memory the next 0
if(game[index] == 1){
rememberIndex0= true;
}
// don't forget incrementing
index += 1;
}
System.out.println(finished?"YES":"NO");
}

Related

Obtaining strictly increasing sequence in array?

I am working on this algorithm problem,
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
I am not sure how to proceed with this?
Hints:
The "strictly increasing" property breaks when an element is immediately followed by a non-larger element. You can detect such a configuration by a simple linear search (and there is no faster way).
Now there are two ways to fix: by removing one of the elements, or the other. Ask yourself if the two choices are equivalent.
Next you need to check that after removal no more inversions exist (by continuing the search from the right point).
The problem is a LeetCode #1909
We can easily check if array is increasing with one item removed, e.g. (c# code):
// if nums is sorted except the item at indexToRemove
public bool IsSorted(int[] nums, int indexToRemove) {
if (nums.Length <= 1)
return true;
int prior = 0;
bool hasPrior = false;
for (int i = 0; i < nums.Length; ++i) {
if (i == indexToRemove) // don't count for item at indexToRemove
continue;
if (!hasPrior)
hasPrior = true;
else if (prior >= nums[i])
return false;
prior = nums[i];
}
return true;
}
Then we can scan the array, and if we have conflict, i.e. array[i - 1] >= array[i] we can try to remove either i-1th or ith item and check if we have an strictly increasing sequence:
public bool CanBeIncreasing(int[] nums) {
if (nums.Length <= 2)
return true;
for (int i = 1; i < nums.Length; ++i) {
if (nums[i - 1] < nums[i]) // no conflict, keep on doing
continue;
// conflict; can we resolve it removing item #i - 1 or item #i?
return IsSorted(nums, i - 1) || IsSorted(nums, i);
}
// no conflicts at all, we don't need to remove any item
return true;
}
Time complexity: O(n) (in the worst case we scan the array 3 times)
Space complexity: O(1)

How to make p consective characters by making k swaps in a String?

There is a String of 1's and 0's for example 110001110. I have given two numbers k and p and I have to check whether I can get atmost p consecutive 1's or 0's by doing k swaps and by swaps I mean if it is 1 then make it 0 and vice versa.
EDIT- I think I have not clearly explained.
For example let the string be 1110000111 and let p = 3 and k = 1. So can I by doing 1 swaps get atmost 3 consective 1's or 0's for which the answer is yes since I can change it into 1110010111.
You could do this in linear time with a straightforward loop. After detecting a monotonous sequence of either all 0 or all 1, you would calculate how many flips would be necessary with a simple formula. These flips can always be made in such a way that the outer digits of that sequence will remain untouched, except for the case where p is 1. In that case the flips must be made to either get 01010101... or else 101010101.... Also that can be done with a simple modulo expression. The best of the two would then be taken (fewer swaps).
Here is an implementation in JavaScript with two sample runs for the generic case (p > 1) and the mentioned special case (p = 1):
function swapsForMaxSequence(s, maxSize) {
var head, tail, swaps;
if (maxSize < 1) return false;
swaps = 0;
if (maxSize === 1) { // Special case
// 0 and 1 should be alternating:
for (head = 0; head < s.length; head++) { // n iterations
if (Number(s[head]) == head % 2) swaps++;
}
// Either the made swaps or the opposite swaps would do it:
return Math.min(swaps, s.length - swaps);
}
tail = 0;
for (head = 1; head <= s.length; head++) { // n iterations
if (head === s.length || s[head] != s[tail]) { // end of sequence?
swaps += Math.floor((head - tail)/(maxSize+1));
tail = head; // Start of new sequence
}
}
return swaps;
}
// Sample input:
var s = '10110101010', // Special case
k = 1,
p = 1;
// Display input:
console.log('s:', s, 'k:', k, 'p:', p);
// Run the algorithm
result = swapsForMaxSequence(s, p);
// Display outcome:
console.log('result:', result);
// Second sample:
var s = '1110000111', // Special case
k = 1,
p = 3;
// Display input:
console.log('s:', s, 'k:', k, 'p:', p);
// Run the algorithm
result = swapsForMaxSequence(s, p);
// Display outcome:
console.log('result:', result);

Moving along a 1D Array

I came across this question in an online coding challenge recently, but I can't seem to make any head way.
There's a 1D array consisting of 0 and 1.
A player starts at index 0 and needs to go beyond the length of the array.
Once the length of the array is crossed the player wins.
The player can only go into indices that have a 0.
A player can move 1 step back, 1 step forward or m steps forward.
The question is how to find out if a game is winnable.
It all boils down to the following function signature:
boolean winnable(int[] arr, int m){
}
Can someone help me with an algorithm to get started.
Added Later
I can up with this algorithm, which of course doesn't pass most of the test cases.
public static boolean winnable(int[] arr, int m){
int currPos = 0;
for(int i=1; i< arr.length; i++){
if(currPos == arr.length -1 - m) return true;
else if(arr[i] == 0)currPos++;
else if(arr[i] == 1){
if(arr[currPos + m] == 0) currPos = currPos + m;
}
}
return false;
}
Iterate over the entire array. For each cell ->
If it is 1, mark it as unreachable. Else, check if it is reachable. A cell is reachable if either
A) the cell before it is reachable
B) the cell m cells before it is reachable.
Once a cell is marked as reachable, you must also mark all consecutive cells behind it which are all '0' as reachable. Once you have marked a cell less than m cells from the end as reachable, that means the end is reachable. If you've marked the last m cells as unreachable, the end is unreachable.
You're going to need a queue, or some other way to remember what indexes need to be checked. Each time you reach a zero that hasn't been seen before, you need to check 3 indexes: the one before, the one after, and the one at distance m.
The size of the queue is limited to the number of zeros in the input array. For example, if the input array has 10 zeros, then the queue can't possibly have more than 10 items in it. So you could implement the queue as a simple array that's the same size as the input array.
Here's some pseudo-code that shows how to solve the problem:
writeToQueue(0)
while ( queue is not empty )
{
index = readFromQueue
if ( index >= length-m )
the game is winnable
array[index] = 1 // mark this index as visited
if ( index > 0 && array[index-1] == 0 ) // 1 step back
writeToQueue(index-1)
if ( array[index+1] == 0 ) // 1 step forward
writeToQueue(index+1)
if ( array[index+m] == 0 ) // m steps forward
writeToQueue(index+m)
}
if the queue empties without reaching the end, the game is not winnable
Note that the input array is used to keep track of which indexes have been visited, i.e. each 0 that is found is changed to a 1, until either the game is won, or no more 0's are reachable.
I just added an accepted solution to this problem on HackerRank.
This is a recursive approach. I created a helper function that would take the currentIndx, array, jumpValue and a Set of visited indices as arguments.
Since currentIndx can't be < 0, I return false;
If currentIndx > arr.length - 1, we are done.
If the value at currentIndx is not 0, we again have to return false since it cannot be in the path.
Now, after these checks we add the visited index to the set. If the add operation returns false, that index must have been visited previously; so we return false.
Then, we recurse. We call the same function with currentIndx - 1, currentIndx + 1 and currentIndx + jumpValue to see what it returns. If any of these are true, we have found a path.
[Java source code]
It can be solved cleanly using BFS. Here goes my solution:
private static boolean isReachable(int[] array, int m) {
boolean[] visited = new boolean[array.length];
Queue<Integer> queue = new LinkedList<>();
queue.add(0);
visited[0] = true;
while (!queue.isEmpty()) {
Integer current = queue.poll();
if (current+m >= array.length) {
return true;
} else if (current+m < array.length && array[current+m] == 0 && !visited[current+m]) {
queue.add(current+m);
visited[current+m] = true;
}
if (current+1 >= array.length) {
return true;
} else if (current+1 < array.length && array[current+1] == 0 && !visited[current+1]) {
queue.add(current+1);
visited[current+1] = true;
}
if (current-1 >= 0 && array[current-1] == 0 && !visited[current-1]) {
queue.add(current-1);
visited[current-1] = true;
}
}
return false;
}

Find length of smallest window that contains all the characters of a string in another string

Recently i have been interviewed. I didn't do well cause i got stuck at the following question
suppose a sequence is given : A D C B D A B C D A C D
and search sequence is like: A C D
task was to find the start and end index in given string that contains all the characters of search string preserving the order.
Output: assuming index start from 1:
start index 10
end index 12
explanation :
1.start/end index are not 1/3 respectively because though they contain the string but order was not maintained
2.start/end index are not 1/5 respectively because though they contain the string in the order but the length is not optimum
3.start/end index are not 6/9 respectively because though they contain the string in the order but the length is not optimum
Please go through How to find smallest substring which contains all characters from a given string?.
But the above question is different since the order is not maintained. I'm still struggling to maintain the indexes. Any help would be appreciated . thanks
I tried to write some simple c code to solve the problem:
Update:
I wrote a search function that looks for the required characters in correct order, returning the length of the window and storing the window start point to ìnt * startAt. The function processes a sub-sequence of given hay from specified startpoint int start to it's end
The rest of the algorithm is located in main where all possible subsequences are tested with a small optimisation: we start looking for the next window right after the startpoint of the previous one, so we skip some unnecessary turns. During the process we keep track f the 'till-now best solution
Complexity is O(n*n/2)
Update2:
unnecessary dependencies have been removed, unnecessary subsequent calls to strlen(...) have been replaced by size parameters passed to search(...)
#include <stdio.h>
// search for single occurrence
int search(const char hay[], int haySize, const char needle[], int needleSize, int start, int * startAt)
{
int i, charFound = 0;
// search from start to end
for (i = start; i < haySize; i++)
{
// found a character ?
if (hay[i] == needle[charFound])
{
// is it the first one?
if (charFound == 0)
*startAt = i; // store starting position
charFound++; // and go to next one
}
// are we done?
if (charFound == needleSize)
return i - *startAt + 1; // success
}
return -1; // failure
}
int main(int argc, char **argv)
{
char hay[] = "ADCBDABCDACD";
char needle[] = "ACD";
int resultStartAt, resultLength = -1, i, haySize = sizeof(hay) - 1, needleSize = sizeof(needle) - 1;
// search all possible occurrences
for (i = 0; i < haySize - needleSize; i++)
{
int startAt, length;
length = search(hay, haySize, needle, needleSize, i, &startAt);
// found something?
if (length != -1)
{
// check if it's the first result, or a one better than before
if ((resultLength == -1) || (resultLength > length))
{
resultLength = length;
resultStartAt = startAt;
}
// skip unnecessary steps in the next turn
i = startAt;
}
}
printf("start at: %d, length: %d\n", resultStartAt, resultLength);
return 0;
}
Start from the beginning of the string.
If you encounter an A, then mark the position and push it on a stack. After that, keep checking the characters sequentially until
1. If you encounter an A, update the A's position to current value.
2. If you encounter a C, push it onto the stack.
After you encounter a C, again keep checking the characters sequentially until,
1. If you encounter a D, erase the stack containing A and C and mark the score from A to D for this sub-sequence.
2. If you encounter an A, then start another Stack and mark this position as well.
2a. If now you encounter a C, then erase the earlier stacks and keep the most recent stack.
2b. If you encounter a D, then erase the older stack and mark the score and check if it is less than the current best score.
Keep doing this till you reach the end of the string.
The pseudo code can be something like:
Initialize stack = empty;
Initialize bestLength = mainString.size() + 1; // a large value for the subsequence.
Initialize currentLength = 0;
for ( int i = 0; i < mainString.size(); i++ ) {
if ( stack is empty ) {
if ( mainString[i] == 'A' ) {
start a new stack and push A on it.
mark the startPosition for this stack as i.
}
continue;
}
For each of the stacks ( there can be at most two stacks prevailing,
one of size 1 and other of size 0 ) {
if ( stack size == 1 ) // only A in it {
if ( mainString[i] == 'A' ) {
update the startPosition for this stack as i.
}
if ( mainString[i] == 'C' ) {
push C on to this stack.
}
} else if ( stack size == 2 ) // A & C in it {
if ( mainString[i] == 'C' ) {
if there is a stack with size 1, then delete this stack;// the other one dominates this stack.
}
if ( mainString[i] == 'D' ) {
mark the score from startPosition till i and update bestLength accordingly.
delete this stack.
}
}
}
}
I modified my previous suggestion using a single queue, now I believe this algorithm runs with O(N*m) time:
FindSequence(char[] sequenceList)
{
queue startSeqQueue;
int i = 0, k;
int minSequenceLength = sequenceList.length + 1;
int startIdx = -1, endIdx = -1;
for (i = 0; i < sequenceList.length - 2; i++)
{
if (sequenceList[i] == 'A')
{
startSeqQueue.queue(i);
}
}
while (startSeqQueue!=null)
{
i = startSeqQueue.enqueue();
k = i + 1;
while (sequenceList.length < k && sequenceList[k] != 'C')
if (sequenceList[i] == 'A') i = startSeqQueue.enqueue();
k++;
while (sequenceList.length < k && sequenceList[k] != 'D')
k++;
if (k < sequenceList.length && k > minSequenceLength > k - i + 1)
{
startIdx = i;
endIdx = j;
minSequenceLength = k - i + 1;
}
}
return startIdx & endIdx
}
My previous (O(1) memory) suggestion:
FindSequence(char[] sequenceList)
{
int i = 0, k;
int minSequenceLength = sequenceList.length + 1;
int startIdx = -1, endIdx = -1;
for (i = 0; i < sequenceList.length - 2; i++)
if (sequenceList[i] == 'A')
k = i+1;
while (sequenceList.length < k && sequenceList[k] != 'C')
k++;
while (sequenceList.length < k && sequenceList[k] != 'D')
k++;
if (k < sequenceList.length && k > minSequenceLength > k - i + 1)
{
startIdx = i;
endIdx = j;
minSequenceLength = k - i + 1;
}
return startIdx & endIdx;
}
Here's my version. It keeps track of possible candidates for an optimum solution. For each character in the hay, it checks whether this character is in sequence of each candidate. It then selectes the shortest candidate. Quite straightforward.
class ShortestSequenceFinder
{
public class Solution
{
public int StartIndex;
public int Length;
}
private class Candidate
{
public int StartIndex;
public int SearchIndex;
}
public Solution Execute(string hay, string needle)
{
var candidates = new List<Candidate>();
var result = new Solution() { Length = hay.Length + 1 };
for (int i = 0; i < hay.Length; i++)
{
char c = hay[i];
for (int j = candidates.Count - 1; j >= 0; j--)
{
if (c == needle[candidates[j].SearchIndex])
{
if (candidates[j].SearchIndex == needle.Length - 1)
{
int candidateLength = i - candidates[j].StartIndex;
if (candidateLength < result.Length)
{
result.Length = candidateLength;
result.StartIndex = candidates[j].StartIndex;
}
candidates.RemoveAt(j);
}
else
{
candidates[j].SearchIndex += 1;
}
}
}
if (c == needle[0])
candidates.Add(new Candidate { SearchIndex = 1, StartIndex = i });
}
return result;
}
}
It runs in O(n*m).
Here is my solution in Python. It returns the indexes assuming 0-indexed sequences. Therefore, for the given example it returns (9, 11) instead of (10, 12). Obviously it's easy to mutate this to return (10, 12) if you wish.
def solution(s, ss):
S, E = [], []
for i in xrange(len(s)):
if s[i] == ss[0]:
S.append(i)
if s[i] == ss[-1]:
E.append(i)
candidates = sorted([(start, end) for start in S for end in E
if start <= end and end - start >= len(ss) - 1],
lambda x,y: (x[1] - x[0]) - (y[1] - y[0]))
for cand in candidates:
i, j = cand[0], 0
while i <= cand[-1]:
if s[i] == ss[j]:
j += 1
i += 1
if j == len(ss):
return cand
Usage:
>>> from so import solution
>>> s = 'ADCBDABCDACD'
>>> solution(s, 'ACD')
(9, 11)
>>> solution(s, 'ADC')
(0, 2)
>>> solution(s, 'DCCD')
(1, 8)
>>> solution(s, s)
(0, 11)
>>> s = 'ABC'
>>> solution(s, 'B')
(1, 1)
>>> print solution(s, 'gibberish')
None
I think the time complexity is O(p log(p)) where p is the number of pairs of indexes in the sequence that refer to search_sequence[0] and search_sequence[-1] where the index for search_sequence[0] is less than the index forsearch_sequence[-1] because it sorts these p pairings using an O(n log n) algorithm. But then again, my substring iteration at the end could totally overshadow that sorting step. I'm not really sure.
It probably has a worst-case time complexity which is bounded by O(n*m) where n is the length of the sequence and m is the length of the search sequence, but at the moment I cannot think of an example worst-case.
Here is my O(m*n) algorithm in Java:
class ShortestWindowAlgorithm {
Multimap<Character, Integer> charToNeedleIdx; // Character -> indexes in needle, from rightmost to leftmost | Multimap is a class from Guava
int[] prefixesIdx; // prefixesIdx[i] -- rightmost index in the hay window that contains the shortest found prefix of needle[0..i]
int[] prefixesLengths; // prefixesLengths[i] -- shortest window containing needle[0..i]
public int shortestWindow(String hay, String needle) {
init(needle);
for (int i = 0; i < hay.length(); i++) {
for (int needleIdx : charToNeedleIdx.get(hay.charAt(i))) {
if (firstTimeAchievedPrefix(needleIdx) || foundShorterPrefix(needleIdx, i)) {
prefixesIdx[needleIdx] = i;
prefixesLengths[needleIdx] = getPrefixNewLength(needleIdx, i);
forgetOldPrefixes(needleIdx);
}
}
}
return prefixesLengths[prefixesLengths.length - 1];
}
private void init(String needle) {
charToNeedleIdx = ArrayListMultimap.create();
prefixesIdx = new int[needle.length()];
prefixesLengths = new int[needle.length()];
for (int i = needle.length() - 1; i >= 0; i--) {
charToNeedleIdx.put(needle.charAt(i), i);
prefixesIdx[i] = -1;
prefixesLengths[i] = -1;
}
}
private boolean firstTimeAchievedPrefix(int needleIdx) {
int shortestPrefixSoFar = prefixesLengths[needleIdx];
return shortestPrefixSoFar == -1 && (needleIdx == 0 || prefixesLengths[needleIdx - 1] != -1);
}
private boolean foundShorterPrefix(int needleIdx, int hayIdx) {
int shortestPrefixSoFar = prefixesLengths[needleIdx];
int newLength = getPrefixNewLength(needleIdx, hayIdx);
return newLength <= shortestPrefixSoFar;
}
private int getPrefixNewLength(int needleIdx, int hayIdx) {
return needleIdx == 0 ? 1 : (prefixesLengths[needleIdx - 1] + (hayIdx - prefixesIdx[needleIdx - 1]));
}
private void forgetOldPrefixes(int needleIdx) {
if (needleIdx > 0) {
prefixesLengths[needleIdx - 1] = -1;
prefixesIdx[needleIdx - 1] = -1;
}
}
}
It works on every input and also can handle repeated characters etc.
Here are some examples:
public class StackOverflow {
public static void main(String[] args) {
ShortestWindowAlgorithm algorithm = new ShortestWindowAlgorithm();
System.out.println(algorithm.shortestWindow("AXCXXCAXCXAXCXCXAXAXCXCXDXDXDXAXCXDXAXAXCD", "AACD")); // 6
System.out.println(algorithm.shortestWindow("ADCBDABCDACD", "ACD")); // 3
System.out.println(algorithm.shortestWindow("ADCBDABCD", "ACD")); // 4
}
I haven't read every answer here, but I don't think anyone has noticed that this is just a restricted version of local pairwise sequence alignment, in which we are only allowed to insert characters (and not delete or substitute them). As such it will be solved by a simplification of the Smith-Waterman algorithm that considers only 2 cases per vertex (arriving at the vertex either by matching a character exactly, or by inserting a character) rather than 3 cases. This algorithm is O(n^2).
Here's my solution. It follows one of the pattern matching solutions. Please comment/correct me if I'm wrong.
Given the input string as in the question
A D C B D A B C D A C D. Let's first compute the indices where A occurs. Assuming a zero based index this should be [0,5,9].
Now the pseudo code is as follows.
Store the indices of A in a list say *orders*.// orders=[0,5,9]
globalminStart, globalminEnd=0,localMinStart=0,localMinEnd=0;
for (index: orders)
{
int i =index;
Stack chars=new Stack();// to store the characters
i=localminStart;
while(i< length of input string)
{
if(str.charAt(i)=='C') // we've already seen A, so we look for C
st.push(str.charAt(i));
i++;
continue;
else if(str.charAt(i)=='D' and st.peek()=='C')
localminEnd=i; // we have a match! so assign value of i to len
i+=1;
break;
else if(str.charAt(i)=='A' )// seen the next A
break;
}
if (globalMinEnd-globalMinStart<localMinEnd-localMinStart)
{
globalMinEnd=localMinEnd;
globalMinStart=localMinStart;
}
}
return [globalMinstart,globalMinEnd]
}
P.S: this is pseudocode and a rough idea. Id be happy to correct it and understand if there's something wrong.
AFAIC Time complexity -O(n). Space complexity O(n)

Binary Search with an unknown number of items

Assuming you don't know the number of elements you are searching and given an API that accepts an index and will return null if you are outside the bounds (as implemented here with the getWordFromDictionary method), how can you perform a binary search and implement the isWordInDictionary() method for client programs?
This solution works, but I ended up doing a serial search above the level where I found an initial high-index value. The search through the lower range of values was inspired by this answer. I also peeked at BinarySearch in Reflector (C# decompiler), but that has a known list length, so still looking to fill in the gaps.
private static string[] dictionary;
static void Main(string[] args)
{
dictionary = System.IO.File.ReadAllLines(#"C:\tmp\dictionary.txt");
Console.WriteLine(isWordInDictionary("aardvark", 0));
Console.WriteLine(isWordInDictionary("bee", 0));
Console.WriteLine(isWordInDictionary("zebra", 0));
Console.WriteLine(isWordInDictionaryBinary("aardvark"));
Console.WriteLine(isWordInDictionaryBinary("bee"));
Console.WriteLine(isWordInDictionaryBinary("zebra"));
Console.ReadLine();
}
static bool isWordInDictionaryBinary(string word)
{
// assume the size of the dictionary is unknown
// quick check for empty dictionary
string w = getWordFromDictionary(0);
if (w == null)
return false;
// assume that the length is very big.
int low = 0;
int hi = int.MaxValue;
while (low <= hi)
{
int mid = (low + ((hi - low) >> 1));
w = getWordFromDictionary(mid);
// If the middle element m you select at each step is outside
// the array bounds (you need a way to tell this), then limit
// the search to those elements with indexes small than m.
if (w == null)
{
hi = mid;
continue;
}
int compare = String.Compare(w, word);
if (compare == 0)
return true;
if (compare < 0)
low = mid + 1;
else
hi = mid - 1;
}
// punting on the search above the current value of hi
// to the (still unknown) upper limit
return isWordInDictionary(word, hi);
}
// serial search, works good for small number of items
static bool isWordInDictionary(string word, int startIndex)
{
// assume the size of the dictionary is unknown
int i = startIndex;
while (getWordFromDictionary(i) != null)
{
if (getWordFromDictionary(i).Equals(word, StringComparison.OrdinalIgnoreCase))
return true;
i++;
}
return false;
}
private static string getWordFromDictionary(int index)
{
try
{
return dictionary[index];
}
catch (IndexOutOfRangeException)
{
return null;
}
}
Final Code after answers
static bool isWordInDictionaryBinary(string word)
{
// assume the size of the dictionary is unknown
// quick check for empty dictionary
string w = getWordFromDictionary(0);
if (w == null)
return false;
// assume that the number of elements is very big
int low = 0;
int hi = int.MaxValue;
while (low <= hi)
{
int mid = (low + ((hi - low) >> 1));
w = getWordFromDictionary(mid);
// treat null the same as finding a string that comes
// after the string you are looking for
if (w == null)
{
hi = mid - 1;
continue;
}
int compare = String.Compare(w, word);
if (compare == 0)
return true;
if (compare < 0)
low = mid + 1;
else
hi = mid - 1;
}
return false;
}
You can implement a binary search in two phases. In the first phase, you grow the size of the interval you're searching in. Once you detect you're outside the bounds, you can do a normal binary search in the latest interval you found. Something like this:
bool isPresentPhase1(string word)
{
int l = 0, d = 1;
while( true ) // you should eventually reach an index out of bounds
{
w = getWord(l + d);
if( w == null )
return isPresentPhase2(word, l, l + d - 1);
int c = String.Compare(w, word);
if( c == 0 )
return true;
else if( c < 0 )
isPresentPhase2(value, l, l + d - 1);
else
{
l = d + 1;
d *= 2;
}
}
}
bool isPresentPhase2(string word, int lo, int hi)
{
// normal binary search in the interval [lo, hi]
}
Sure you can. Start at index one, and double your query index until you hit something that's lexographically larger than your query word(Edit: or null). Then you can narrow down your search space again until you find the index, or return false.
Edit: Note that this does NOT add to your asymptotic runtime, and it is still O(logN), where N is the number of items in the series.
So, I'm not sure I entirely understand the problem from your description, but I'm assuming you're trying to search through a sorted array of unknown length to find a particular string. I'm also assuming that there are no nulls in the actual array; the array only returns null if you ask for an index that's out of bounds.
If those things are true, the solution should be just a standard binary search, albeit one where you search over the entire integer space, and you just treat null the same as finding a string that comes after the string you are looking for. Essentially just imagine that your sorted array of N strings is really a sorted array of INT_MAX strings sorted with nulls at the end.
What I don't quite understand is that you seem to basically have done that already (at least from a cursory look at the code), so I think I might not understand your problem completely.

Resources