java-recursively finding a specific path in array - java

i would like to know to can i calculate 2 specific paths in a given array.
how can i return the shortest (or longest) path from [0][0] to [m][n]? i manage to progress through the array recursively but i don't know how i can "save" the paths and check which one is smaller to return.
this one's a bit more specific and complicated- each cell has an integer (pos/neg), and valid progressions in the array are n+1 or m+1. i would like to add each cell's value and return the lowest possible number that will guarantee a positive sum of all the cells from [0][0] to [n][m]. for example, if the lowest sum of path x is -3, the number returned will be 4 (4-3=1).
the 2nd request is a question i've been stuck at for quite a while but i've seen other questions regarding using and calculating stuff with the values in those arrays.

As you haven't been very descriptive I'll just try to explain the basic concept as well as I can.
1) Check if the current coordinate has reached a goal, return the current sum. This is the base case.
2) Check if the current steps taken exceeds the maximum number of steps needed to prevent infinite reccurrsion. This is the fail case, necessary when using breadth first search.
3) Check if the next desired position you are walking to is within the grid, and hasn't been visited before. Mark it as visited and save the sum from that path. When you get back, mark that position as not visited and try the next move available... and so on for all possible directions.
4) When all possible paths have been tried compare their results to see which was the smallest one and return that as a solution.
Example using depth first recurssion:
public void solve(int[][] a, boolean[][] visited, int sum, int steps, int x, int y, int xMax, int yMax) {
if (isSolved(x, y)) { // Base case - solved
return sum;
}
if (steps > MAX_STEPS) {
return Integer.MAX_VALUE; // Return invalid if the algorithm exceeds maximum steps to prevent unlimited seek time
}
int[] path = new int[NUM_PATHS]; // An array holding the calculated paths for all possible options. Should
for (int i = 0; i < NUM_PATHS; i++) {
path[i] = Integer.MAX_VALUE; // Should be set to fail case as default.
}
if (canReach(x + 1, y) && !visited[y][x +1]) {
visited[y][x + 1] = true;
path[0] = solve(a, visited, sum + a[y][x + 1] steps + 1, x + 1, y, xMax, yMax);
visited[y][x + 1] false;
}
if (canReach(x - 1, y) && !visited[y][x - 1]) {
...
}
... etc
// Finding the best solution
min = path[0];
for (int i = 1; i < path.length; i++) {
if (path[i] < min)
min = path[i];
}
return min;
}
With dynamic programming you can optimize your algorithm to disregard paths that are worse than the previously found best, thus shortening the recursions needed.
Also if you want to save the path taken you do that through an ArrayList and add/remove it as you do when you mark a node as visited.

Related

Dynamic Programming Problem: Minimizing A Path Through Array

I'm working on a problem right now where we are provided with a 1D array of values, and must find the path from the first index to the last index that sums to the smallest sum. The only restrictions are that if you go forward, the distance you go must be 1 more than the last "jump", while if you go backwards, you must go the same distance as the last "jump". For instance, given an array int[] values = new int[]{4, 10, 30, 1, 6}, you need to find the path that gets you from position 0 (4) to position 4 (6) that sums up to the smallest amount. The starting indice is not counted, thus, if I go from values[0] to values[1] (which is the only possible starting move), my running total at that point would be 10. From there, I either have the choice to "jump" back the same distance (to values[0]), or "jump" one distance longer than my last jump, which would then be 1+1=2, so jump from values[1] to values[3].
I'm really new to dynamic programming and attempted a solution that went something like this
public static int smallestCalc(int[] values, int prevJump, int pos, int runTot) {
while (pos != penal.length) {
int forwards = 600;
int backwards = 600;
try {
backwards = penal[pos - prevJump];
} catch (Exception ignore) {}
try {
forwards = penal[pos + prevJump+1];
} catch (Exception ignore) {}
int min = Math.min(forwards,backwards);
if (min == backwards) {
pos -= prevJump;
} else {
pos += prevJump + 1;
prevJump ++;
}
runTot+=min;
smallestCalc(values, prevJump, pos, runTot);
}
return runTot;
}
However, I recognize that I'm not actually making use of a dynamic programming table here, but I'm not exactly sure what I would store inside that I need to "remember" across calculations, or how I could even utilize it in calculations. From what I see, it appears that I basically have to make a recursive function that evaluates all possible jump distances from an index, store them, and then traverse through the DP table to find the smallest amount? Should I be starting from the last index or the first index of the array to limit possible moves? I watched this video here, and understood the premise, but it seems much more applicable to his 2D Array than anything I have. Any amount of guidance here would be greatly appreciated.
In my opinion, this is a 2D DP problem.
dp(i, j) represents the minimum sum required to reach last index from index i and minimum jump allowed of size j.
Let's say you are at index i in the array. Then you can either go to index i-j+1 or index i+j.
So,
int recur(int values[], int i, int j){
// base case. Here n is size of values array
if(i==n-1)
return 0;
if(dp[i][j] != -1){
/* here -1 is taken as to mark never calculated state of dp.
If the values[] array also contains negative values then you need to change it to
something appropriate.
*/
return dp[i][j];
}
int a = INT_MAX;
int b = a;
if(i>0 && (i-j+1)>=0)
a = values[i-j + 1] + recur(values, i-j+1, j);
if(i+j < n)
b = values[i+j] + recur(values, i+j, j+1);
return dp[i][j] = min(a, b);
}
Time and space complexity O(n * n).
Edit:
Initial function call is recur(values, 0, 1).
I know that the tag of this question is java but I do competitive programming in c++ only. Here I have full working code if you want in c++.

Is this method to get the closest number in a sorted List most effective?

I have large arrays of integers (with sizes between 10'000 and 1'400'000). I want to get the first integer bigger to a value. The value is never inside the array.
I've looked for various solutions but I have only found :
methods that estimate each values and are not designed for sorted lists or arrays (with O(n) time complexity).
methods that are recursive and/or not designed for very large lists or arrays (with O(n) or more time complexity, in other languages though, so I'm not sure).
I've designed my own method. Here it is :
int findClosestBiggerInt(int value, int[] sortedArray) {
if( sortedArray[0]>value ||
value>sortedArray[sortedArray.length-1] ) // for my application's convenience only. It could also return the last.
return sortedArray[0];
int exp = (int) (Math.log(sortedArray.length)/Math.log(2)),
index = (int) Math.pow(2,exp);
boolean dir; // true = ascend, false = descend.
while(exp>=0){
dir = sortedArray[Math.min(index, sortedArray.length-1)]<value;
exp--;
index = (int)( index+ (dir ? 1 : -1 )*Math.pow(2,exp) );
}
int answer = sortedArray[index];
return answer > value ? answer : sortedArray[index+1];
}
It has a O(log n) time complexity. With an array of length 1'400'000, it will loop 21 times inside the while block. Still, I'm not sure that it cannot be improved.
Is there a more effective way to do it, without the help of external packages ? Any time saved is great because this calculation occurs quite frequently.
Is there a more effective way to do it, without the help of external packages ? Any time saved is great because this calculation occurs quite frequently.
Well here is one approach that uses a map instead of an array.
int categorizer = 10_000;
// Assume this is your array of ints.
int[] arrayOfInts = r.ints(4_000, 10_000, 1_400_000).toArray();
You can group them in a map like so.
Map<Integer, List<Integer>> ranges =
Arrays.stream(arrayOfInts).sorted().boxed().collect(
Collectors.groupingBy(n -> n / categorizer));
Now, when you want to find the next element higher, you can get the list that would contain the number.
Say you want the next number larger than 982,828
int target = 982,828;
List<Integer> list = map.get(target/categorizer); // gets the list at key = 98
Now just process the list with your favorite method. One note. In some circumstances it is possible that your highest number could be in the other lists that come after this one, depending on the gap. You would need to account for this, perhaps by adjusting how the numbers are categorized or by searching subsequent lists. But this can greatly reduce the size of the lists you're working with.
As Gene's answer indicates, you can do this with binary search. The built-in java.util.Arrays class provides a binarySearch method to do that for you:
int findClosestBiggerInt(final int value, final int[] sortedArray) {
final int index = Arrays.binarySearch(sortedArray, value + 1);
if (index >= 0) {
return sortedArray[index];
} else {
return sortedArray[-(index + 1)];
}
}
You'll find that to be much faster than the method you wrote; it's still O(log n) time, but the constant factors will be much lower, because it doesn't perform expensive operations like Math.log and Math.pow.
Binary search is easily modified to do what you want.
Standard binary search for exact match with the target maintains a [lo,hi] bracket of integers where the target value - if it exists - is always inside. Each step makes the bracket smaller. If the bracket ever gets to size zero (hi < lo), the element is not in the array.
For this new problem, the invariant is exactly the same except for the definition of the target value. We must take care never to shrink the bracket in a way that might eliminate the next bigger element.
Here's the "standard" binary search:
int search(int tgt, int [] a) {
int lo = 0, hi = a.length - 1;
// loop while the bracket is non-empty
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
// if a[mid] is below the target, ignore it and everything smaller
if (a[mid] < tgt) lo = mid + 1;
// if a[mid] is above the target, ignore it and everything bigger
else if (a[mid] > tgt) hi = mid - 1;
// else we've hit the target
else return mid;
}
// The bracket is empty. Return "nothing."
return -1;
}
In our new case, the part that obviously needs a change is:
// if a[mid] is above the target, ignore it and everything bigger
else if (a[mid] > tgt) hi = mid - 1;
That's because a[mid] might be the answer. We can't eliminate it from the bracket. The obvious thing to try is keep a[mid] around:
// if a[mid] is above the target, ignore everything bigger
else if (a[mid] > tgt) hi = mid;
But now we've introduced a new problem in one case. If lo == hi, i.e. the bracket has shrunk to 1 element, this if doesn't make progress! It sets hi = mid = lo + (hi - lo) / 2 = lo. The size of the bracket remains 1. The loop never terminates.
Therefore, the other adjustment we need is to the loop condition: stop when the bracket reaches size 1 or less:
// loop while the bracket has more than 1 element.
while (lo < hi) {
For a bracket of size 2 or more, lo + (hi - lo) / 2 is always smaller than hi. Setting hi = mid makes progress.
The last modification we need is checking the bracket after the loop terminates. There are now three cases rather than one in the original algorithm:
empty or
contains one element, which is the answer,
or it's not.
It's easy to sort these out just before returning. In all, we have:
int search(int tgt, int [] a) {
int lo = 0, hi = a.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < tgt) lo = mid + 1;
else if (a[mid] > tgt) hi = mid;
else return mid;
}
return lo > hi || a[lo] < tgt ? -1 : lo;
}
As you point out, for a 1.4 million element array, this loop will execute no more than 21 times. My C compiler produces 28 instructions for the whole thing; the loop is 14. 21 iterations ought to be a handful of microseconds. It requires only small constant space and generates zero work for the Java garbage collector. Hard to see how you'll do better.

Random search algorithm using recursion

So I'm quite new to algorithms and have never programmed with recursion so I apologize in advance if I am missing something stupid.
I am trying to make a search algorithm that I believe would work similarly to something like binary search.
Lets call the element im searching for x (like x marks the spot)
So I search a random index in a sorted array
If element < x
lowerbound = index + 1 //to create a sub array
If element > x
upperbound = index - 1 //to create a sub array
Repeat process until find x in array.
The problem I am having is making it so my random number only searches within the bounds. If i go rand.nextInt(upperbound) like I have in my code it just keeps searching to the left. I need to be able to search it to the left or right. Is there a better random number method for this? Does anyone have any idea how I could possible implement this algorithm? The code below is a day and a halves work and I am pretty disappointed in myself at this point to be honest.
Also I know I also need to consider the case if my array doesn't contain x at all but i want to get the basic search mechanism sorted first.
Any help would be most appreciate.
private static int counter = 0;
public static int searchRan(int Array[], int x, int low, int up)
{
counter++;
Random rand = new Random();
int select = rand.nextInt(up);
System.out.println(select);
if(Array[select] == x)
{
System.out.printf("Found %d after %d recursion", x, counter);
return select;
}
else if(Array[select] < x)
{
return searchRan(Array, x, select + 1, up);
}
else if(Array[select] > x)
{
return searchRan(Array, x, low, select - 1);
}
else
{
return 666;
}
}
public static void main(String[] args){
int sortedArray[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int lowerbound = 0;
int upperbound = sortedArray.length - 1;
int target = 0;
System.out.println(searchRan(sortedArray, 0, lowerbound, upperbound));
}
Try generating your probe index like this:
int select = low + rand.nextInt(up - low + 1);
The search ends in failure when low > up; that should be the first thing you check in your search routine.
Since your array is already sorted you need to get the middle element to consistently search either left array or right array.
int middle = (start + end) / 2;
Please refer this link below.
How to use recursion in creating a binary search algorithm
Why re invent the wheel, Since the array is already sorted just use binary search algorithm.
Step 1 − Start searching data from the middle of the list.
Step 2 − If it is a match, return the index of the item, and exit.
Step 3 − If it is not a match, probe position.
Step 4 − Divide the list using probing formula and find the new middle.
Step 5 − If data is greater than the middle, search in higher sub-list.
Step 6 − If data is smaller than the middle, search in lower sub-list.
Step 7 − Repeat until the match.
Problem of your code:
variable up is getting negative value or zero.
It should be always greater than zero.
Try to make it greater than zero always.
Sometimes low>up . You need to fix it .
Then you are all okay.

How to find minimum number of jumps to reach the end of the array in O(n) time

Question
Given an array of integers where each element represents the max number of steps that can be made forward from that element.
Write a function to return the minimum number of jumps to reach the
end of the array (starting from the first element). If an element is
0, then cannot move through that element.
Example
Input: arr[] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}
Output: 3 (1-> 3 -> 8 ->9)
Found multiple ways from Dynamic Programming approach to other linear approaches. I am not able to understand the approach which is said to linear in time. HERE is the link where a linear approach is proposed.
I am not able to understand it at all. What I could understand is that author is suggesting to do a greedy approach and see if we reach end .. if not then backtrack ?
The time complexity of the solution proposed on the site is linear because you only iterate over the array once. The algorithm avoids the inner iteration of my proposed solution by using some clever tricks.
The variable maxReach stores at all time the maximal reachable position in the array. jump stores the amount of jumps necessary to reach that position. step stores the amount of steps we can still take (and is initialized with the amount of steps at the first array position)
During the iteration, the above values are updated as follows:
First we test whether we have reached the end of the array, in which case we just need to return the jump variable.
Next we update the maximal reachable position. This is equal to the maximum of maxReach and i+A[i] (the number of steps we can take from the current position).
We used up a step to get to the current index, so steps has to be decreased.
If no more steps are remaining (i.e. steps=0, then we must have used a jump. Therefore increase jump. Since we know that it is possible somehow to reach maxReach, we initialize the steps to the amount of steps to reach maxReach from position i.
public class Solution {
public int jump(int[] A) {
if (A.length <= 1)
return 0;
int maxReach = A[0];
int step = A[0];
int jump = 1;
for (int i = 1; i < A.length; i++) {
if (i == A.length - 1)
return jump;
if (i + A[i] > maxReach)
maxReach = i + A[i];
step--;
if (step == 0) {
jump++;
step = maxReach - i;
}
}
return jump;
}
}
Example:
int A[] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}
int maxReach = A[0]; // A[0]=1, so the maximum index we can reach at the moment is 1.
int step = A[0]; // A[0] = 1, the amount of steps we can still take is also 1.
int jump = 1; // we will always need to take at least one jump.
/*************************************
* First iteration (i=1)
************************************/
if (i + A[i] > maxReach) // 1+3 > 1, we can reach further now!
maxReach = i + A[i] // maxReach = 4, we now know that index 4 is the largest index we can reach.
step-- // we used a step to get to this index position, so we decrease it
if (step == 0) {
++jump; // we ran out of steps, this means that we have made a jump
// this is indeed the case, we ran out of the 1 step we started from. jump is now equal to 2.
// but we can continue with the 3 steps received at array position 2.
steps = maxReach-i // we know that by some combination of 2 jumps, we can reach position 4.
// therefore in the current situation, we can minimaly take 3
// more steps to reach position 4 => step = 3
}
/*************************************
* Second iteration (i=2)
************************************/
if (i + A[i] > maxReach) // 2+5 > 4, we can reach further now!
maxReach = i + A[i] // maxReach = 7, we now know that index 7 is the largest index we can reach.
step-- // we used a step so now step = 2
if (step==0){
// step
}
/*************************************
* Second iteration (i=3)
************************************/
if (i + A[i] > maxReach) // 3+8 > 7, we can reach further now!
maxReach = i + A[i] // maxReach = 11, we now know that index 11 is the largest index we can reach.
step-- // we used a step so now step = 1
if (step==0){
// step
}
/*************************************
* Third iteration (i=4)
************************************/
if (i + A[i] > maxReach) // 4+9 > 11, we can reach further now!
maxReach = i + A[i] // maxReach = 13, we now know that index 13 is the largest index we can reach.
step-- // we used a step so now step = 0
if (step == 0) {
++jump; // we ran out of steps, this means that we have made a jump.
// jump is now equal to 3.
steps = maxReach-i // there exists a combination of jumps to reach index 13, so
// we still have a budget of 9 steps
}
/************************************
* remaining iterations
***********************************
// nothing much changes now until we reach the end of the array.
My suboptimal algorithm which works in O(nk) time with n the number of elements in the array and k the largest element in the array and uses an internal loop over array[i]. This loop is avoided by the below algorithm.
Code
public static int minimum_steps(int[] array) {
int[] min_to_end = new int[array.length];
for (int i = array.length - 2; i >= 0; --i) {
if (array[i] <= 0)
min_to_end[i] = Integer.MAX_VALUE;
else {
int minimum = Integer.MAX_VALUE;
for (int k = 1; k <= array[i]; ++k) {
if (i + k < array.length)
minimum = Math.min(min_to_end[i+k], minimum);
else
break;
}
min_to_end[i] = minimum + 1;
}
}
return min_to_end[0];
}
Here is the basic intuition regarding the above problem's greedy approach and rest are the code requirements.
Given array is Input: a[] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}.
Now we start from the 1st element i.e i=0 and a[i] = 1. So seeing this we can take at most a jump of size 1, so since we don't have any other choice so we make this step happen.
Currently we are at i=1 and a[i]=3. So we currently can make a jump of size 3, but instead we consider all possible jumps we can make from the current location and attain the maximum distance which is within bounds(of the array). So what are our choices? we can make a jump of 1 step, or 2 steps or 3 steps. So we investigate from current location for each size jumps and choose the one which can take us maximum further into the array.
Once we have decided, which one we stick to, we take that jump size and update our number of jumps made so far and also where we can reach at most and how many steps we have now to decide our next move. And that's it. This is how finally we select the best option linearly traversing the array.
So this is the basic idea of the algo you might be looking for, next is to code it for the algorithm to work. Cheers!
Hope somebody time travels and finds the intuition helpful !! :) :P
"Years late to the party" #Vasilescu Andrei - well said. Sometimes it feels to me that we are time travelers.
Many of the answers here so far are great, but I feel I can help explain why the algorithm is correct and the intuition behind it.
I like this problem because it's one where the intuitive dynamic programming approach runs in O(n^2) worst-case, and a greedy approach (the one that motivated this question) runs in O(n) worst-case (it actually only visits each element of the array once). This algorithm is also for me somewhat reminiscent of Dijkstra's algorithm which solves another single-source shortest-path problem and that is also greedy.
To start, remember from the problem statement that A[i] holds the maximum position you can jump to from that index, but you can take a shorter jump from i if A[i]>1, so a shortest sequence of jumps from i=0 could be one with shorter jumps than what's allowed on each index. This is important, since you will see that the algorithm never considers those smaller jumps or their locations explicitly.
Second, it helps to think of the algorithm that you mentioned as one that gives itself "strands of rope" (steps = maxReach - i;) to reach the end, and that it consumes this rope (steps--;) as it tries to advance through the array.
Third, note that the algorithm is not keeping track of the specific indices i that may be part of a shortest sequence from the beginning to the end of the input array A. In fact, the algorithm only increases the variable jump (it gives itself a new strand of rope) when it "runs out of rope" (from the previous strand), so that it can keep iterating in the main loop to "try" to reach the end.
More specifically for the algorithm to be correct it needs to:
Keep track of "how far it can reach" (maxReach) from each location i as it moves forward through the array. Note that this quantity is updated for each location even if it's clear already at that moment that reaching that new location will require it to take more "jumps" as you exceed the number of steps (i.e. you run out of rope) that you gave yourself earlier, even if no shortest path would actually visit that element. The goal of these updates is to identify how far the next jump could reach so that it can give itself that much rope once it exhausted the current one.
Account for the minimum number of jumps (jumps) you must take if you want to continue iterating through the array to reach the end, as you run out of rope (steps) from the previous strand.
The algorithm that you linked to, for reference:
public class Solution {
public int jump(int[] A) {
if (A.length <= 1)
return 0;
int maxReach = A[0];
int step = A[0];
int jump = 1;
for (int i = 1; i < A.length; i++) {
if (i == A.length - 1)
return jump;
if (i + A[i] > maxReach)
maxReach = i + A[i];
step--;
if (step == 0) {
jump++;
step = maxReach - i;
}
}
return jump;
}
}
Years late to the party , but here is another O(n) solution that made sense for me.
/// <summary>
///
/// The actual problem is if it's worth not to jump to the rightmost in order to land on a value that pushes us further than if we jumped on the rightmost.
///
/// However , if we approach the problem from the end, we go end to start,always jumping to the leftmost
///
/// with this approach , these is no point in not jumping to the leftmost from end to start , because leftmost will always be the index that has the leftmost leftmost :) , so always choosing leftmost is the fastest way to reach start
///
/// </summary>
/// <param name="arr"></param>
static void Jumps (int[] arr)
{
var LeftMostReacher = new int[arr.Length];
//let's see , for each element , how far back can it be reached from
LeftMostReacher[0] = -1; //the leftmost reacher of 0 is -1
var unReachableIndex = 1; //this is the first index that hasn't been reached by anyone yet
//we use this unReachableIndex var so each index's leftmost reacher is the first that was able to jump to it . Once flagged by the first reacher , new reachers can't be the leftmost anymore so they check starting from unReachableIndex
// this design insures that the inner loop never flags the same index twice , so the runtime of these two loops together is O(n)
for (int i = 0; i < arr.Length; i++)
{
int maxReach = i + arr[i];
for (; unReachableIndex <= maxReach && unReachableIndex < arr.Length; unReachableIndex++)
{
LeftMostReacher[unReachableIndex] = i;
}
}
// we just go back from the end and then reverse the path
int index = LeftMostReacher.Length - 1;
var st = new Stack<int>();
while (index != -1)
{
st.Push(index);
index = LeftMostReacher[index];
}
while (st.Count != 0)
{
Console.Write(arr[st.Pop()] + " ");
}
Console.WriteLine();
}
static void Main ()
{
var nrs = new[] { 1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9 };
Jumps(nrs);
}
Simple python code for the Minimum number of jumps to reach end problem.
ar=[1, 3, 6, 3, 2, 3, 6, 8, 9, 5]
minJumpIdx=0
res=[0]*len(ar)
i=1
while(i<len(ar) and i>minJumpIdx):
if minJumpIdx+ar[minJumpIdx]>=i:
res[i]=res[minJumpIdx]+1
i+=1
else:
minJumpIdx+=1
if res[-1]==0:
print(-1)
else:
print(res[-1])
Here is another linear solution. The code is longer than the one suggested in the leet code link, but I think it is easier to understand. It is based on a two observations: the number of steps required to reach the i + 1 position is never less than the number of steps required to reach the i position and each element each element assigns its value + 1 to i + 1 ... i + a[i] segment.
public class Solution {
public int jump(int[] a) {
int n = a.length;
// count[i] is the number of "open" segments with value i
int[] count = new int[n];
// the number of steps to reach the i-th position
int[] dp = new int[n];
Arrays.fill(dp, n);
// toDelete[i] is the list of values of segments
// that close in the i-th position
ArrayList<Integer>[] toDelete = new ArrayList[n];
for (int i = 0; i < n; i++)
toDelete[i] = new ArrayList<>();
// Initially, the value is 0(for the first element).
toDelete[0].add(0);
int min = 0;
count[0]++;
for (int i = 0; i < n; i++) {
// Finds the new minimum. It uses the fact that it cannot decrease.
while (min < n && count[min] == 0)
min++;
// If min == n, then there is no path. So we can stop.
if (min == n)
break;
dp[i] = min;
if (dp[i] + 1 < n) {
// Creates a new segment from i + 1 to i + a[i] with dp[i] + 1 value
count[dp[i] + 1]++;
if (i + a[i] < n)
toDelete[i + a[i]].add(dp[i] + 1);
}
// Processes closing segments in this position.
for (int deleted : toDelete[i])
count[deleted]--;
}
return dp[n - 1];
}
}
Complexity analysis:
The total number of elements in toDelete lists is O(n). It is the case because at each position i at most one element is added. That's why processing all elements in all toDelete lists requires linear time.
The min value can only increase. That's why the inner while loop makes at most n iterations in total.
The outer for loop obviously makes n iterations. Thus, the time complexity is linear.
Okay, it took me good amount of time to wrap my head around the O(n) algo, I will try to explain the logic to my best simplest possible:
At each "i" in the array, you know with that value what is the currentFarthest value, you can reach up to, & also the currentEnd value, whenever you hit the currentEnd value, you know its time to make a jump & update currentEnd with currentFarthest.
The picture below might help :
I have done this with Python.
Less complex code with simple terms. This might help you.
def minJump(a):
end=len(a)
count=0
i=a[0]
tempList1=a
while(i<=end):
if(i==0):
return 0
tempList1=a[count+1:count+i+1]
max_index=a.index(max(tempList1))
count+=1
i=a[max_index]
end=end-max_index
return count+1
Another O(n) Solution With the best explanation
The following solution provides with o(n) time complexity
For solving minimum jumps to reach the end of the array,
For every jump index, we consider need to evaluate the corresponding step values in the index and using the index value divides the array into sub-parts and find out the maximum steps covered index.
Following code and explanation will give you a clear idea:
In each sub-array find out the max distance covered index as the first part of the array, and the second array
Input Array : {1, 3, 5, 9, 6, 2, 6, 7, 6, 8, 9} -> index position starts with 0
Steps :
Initial step is considering the first index and incrementing the jump
Jump = 1
1, { 3, 5, 9, 6, 2, 6, 7, 6, 8, 9} -> 1 is considered as a first jump
next step
From the initial step there is only one step to move so
Jump = 2
1,3, { 5, 9, 6,2, 6, 7, 6, 8, 9} -> 1 is considered as a first jump
next step
Now we have a flexibility to choose any of {5,9,6} because of last step says we can move upto 3 steps
Consider it as a subarray, evaluate the max distance covers with each index position
As {5,9,6} index positions are {2,3,4}
so the total farther steps we can cover:
{7,12,10} -> we can assume it as {7,12} & {10} are 2 sub arrays where left part of arrays says max distance covered with 2 steps and right side array says max steps cover with remaining values
next step:
Considering the maximum distanc covered in first array we iterate the remaining next elements
1,3,9 {6,2, 6, 7, 6, 8, 9}
From above step ww already visited the 4th index we continue with next 5th index as explained above
{6,2, 6, 7, 6, 8, 9} index positions {4,5,6,7,8,9,10}
{10,7,12,14,14,17,19}
Max step covers here is 19 which corresponding index is 10
Code
//
// Created by Praveen Kanike on 07/12/20.
//
#include <iostream>
using namespace std;
// Returns minimum number of jumps
// to reach arr[n-1] from arr[0]
int minJumps(int arr[], int n)
{
// The number of jumps needed to
// reach the starting index is 0
if (n <= 1)
return 0;
// Return -1 if not possible to jump
if (arr[0] == 0)
return -1;
// stores the number of jumps
// necessary to reach that maximal
// reachable position.
int jump = 1;
// stores the subarray last index
int subArrEndIndex = arr[0];
int i = 1;
//maximum steps covers in first half of sub array
int subArrFistHalfMaxSteps = 0;
//maximum steps covers in second half of sub array
int subArrSecondHalfMaxSteps =0;
// Start traversing array
for (i = 1; i < n;) {
subArrEndIndex = i+subArrEndIndex;
// Check if we have reached the end of the array
if(subArrEndIndex >= n)
return jump;
int firstHalfMaxStepIndex = 0;
//iterate the sub array and find out the maxsteps cover index
for(;i<subArrEndIndex;i++)
{
int stepsCanCover = arr[i]+i;
if(subArrFistHalfMaxSteps < stepsCanCover)
{
subArrFistHalfMaxSteps = stepsCanCover;
subArrSecondHalfMaxSteps = 0;
firstHalfMaxStepIndex = i;
}
else if(subArrSecondHalfMaxSteps < stepsCanCover)
{
subArrSecondHalfMaxSteps = stepsCanCover;
}
}
if(i > subArrFistHalfMaxSteps)
return -1;
jump++;
//next subarray end index and so far calculated sub array max step cover value
subArrEndIndex = arr[firstHalfMaxStepIndex];
subArrFistHalfMaxSteps = subArrSecondHalfMaxSteps;
}
return -1;
}
// Driver program to test above function
int main()
{
int arr[] = {100, 3, 5, 9, 6, 2, 6, 7, 6, 8, 9};
int size = sizeof(arr) / sizeof(int);
// Calling the minJumps function
cout << ("Minimum number of jumps to reach end is %d ",
minJumps(arr, size));
return 0;
}
Just in case you need to write a python solution for the greedy approach this code will get you covered for the above problem :)
def minJumps(self, arr, n):
#code here
if(n <= 1):
return(0)
if(arr[0] == 0):
return -1
maxrange, step = arr[0], arr[0]
jumps = 1
for i in range(1,n):
if (i == len(arr) - 1):
return jumps
maxrange = max(maxrange, i+arr[i])
step -= 1
if(step == 0):
jumps += 1
if(i>=maxrange):
return -1
step = maxrange - i
return(jumps)
Here is another solution. In this solution, the worst-case complexity is O(n) while the average-case complexity is less than O(n). I don't know how to do average-case complexity analysis. So, I can't tell the exact average-case complexity. But yeah it is faster than 99.22% of submissions on leet code.
def minJumps(self, arr, n):
current_w=0 # current_index
last_w=n-1 # last_index
max_reach=0 # value of index upto which we have analysed array for optimum solution
max_jumps=arr[0] # maximum jumps that can be taken from a current_index
hop=0 # total jumps
while current_w<last_w:
max_jumps=arr[current_w]
if max_jumps==0:
return -1
if max_jumps==1:
max_reach=max_jumps+current_w
current_w+=1
elif max_jumps<last_w-current_w: # if maximum steps does not reach to last index
can_jump_to=arr[max_reach+1:max_jumps+current_w+1] # subarray in which we have to search for a wall,jumping to which can take us to required solution
jump_to=max(range(len(can_jump_to)),key=lambda x: x+can_jump_to[x])+max_reach+1 # finding index of wall whoose definition mentioned in above comment
max_reach=max_jumps+current_w #updating max_reach
current_w=jump_to #updating current position
else:
current_w=last_w
hop+=1
return hop
static void minJumps(int a[] , int n)
{
int dp[] = new int[n];
dp[0] = 0; //As the min jumps needed to get to first index is zero only.
//Fill the rest of the array with INT_MAX val so we can make math.min comparisions.
for(int i=1;i<n;i++)
dp[i] = Integer.MAX_VALUE;
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{ //If we have enough jumps from the position j to reach i.
if(j+a[j]>=i)
{ //Take the min of current stored value & jumps req to
//reach i from j by getting jumps req to reach j plus 1.
//(Plus 1 because since we have enough jumps to reach 1 from j we
//simply add 1 by taking the jumps required to reach j.)
dp[i] = Math.min(dp[i],dp[j]+1);
}
}
}
//If first element has zero jumps in store or if the final jumps value
//becomes MAX value because there's an element in between which gives zero
//jumps.
if(a[0]==0 || dp[n-1] == Integer.MAX_VALUE )
System.out.println("-1");
else System.out.println(dp[n-1]);
}

How to determine if position Z is within regions with start X and end Y

I have a JTextArea where the user can create regions using special syntax. I am looking for some assistance in the best way (most efficient using a linear time algorithm) to determine if the current position is within one of the non-overlapping regions.
Let's assume I have the following to determine the user defined regions (I scan the document at the start using regex to determine the regions):
REGION START = 0, END = 20
REGION START = 21, END = 24
REGION START = 34, END = 40
I don't care what region the user is in, I just need to determine if they are in or out of a region, given position X. I could store the regions as an array and loop through the entries until I find one that matches, but this isn't linear time and would take longer if it didn't match a region.
Is there an easier way to do this using an algorithm or storing the data in a certain way?
Actually the algorithm you are proposing is indeed linear. Here is another one, a bit more complicated, but faster:
You need to use a Cumulative Table data structure, like Binary Indexed Tree (BIT). A BIT allows you to implement the following operations with logarithmic complexity:
Update lo, hi, val: add at the indices [lo, hi] the value val
Query x: return the sum at index x
For each region [lo, hi], you call Update(lo, hi, 1), adding 1 to the appropriate positions in the BIT
For each query just check if Query(x) is zero. If yes, then x, does not overlap with a region
About Binary Indexed Trees: http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees
And some code:
public class BIT {
// AddAtPosition: adds at binary indexed tree [bit] the value [v]
// exactly at position [i]. The binary indexed tree has size [size]
public static void AddAtPosition(int [] bit, int size, int i, int v) {
while(i < size) {
bit[i] += v;
i += (i & -i);
}
}
// AddAtInterval: adds at binary indexed tree [bit] the value [v]
// to all position from [lo] to [hi]. The binary indexed tree has size [size]
public static void AddAtInterval(int [] bit, int size, int lo, int hi, int v) {
AddAtPosition(bit, size, lo+1, v);
AddAtPosition(bit, size, hi+2, -v);
}
// QueryAtPosition: returns the value of index [i] at binary indexed tree [bit]
public static int QueryAtPosition(int [] bit, int i) {
int ans = 0;
i++;
while(i > 0) {
ans += bit[i];
i -= (i & -i);
}
return ans;
}
public static void main(String [] args) {
int [] bit = new int[10+1]; // for values from 0-9
AddAtInterval(bit, 11, 0, 5, 1);
AddAtInterval(bit, 11, 4, 7, 1);
for(int i=0; i<=9; ++i) {
System.out.print("Query At position " + i + ": ");
System.out.println(QueryAtPosition(bit, i));
}
}
}
I could store the regions as an array and loop through the entries
until I find one that matches, but this isn't linear time
It is linear.
Assuming that regions are sorted, you could use Binary Search.
Although I like the BIT example, I think I might use a simpler solution which I am hoping doesn't have a huge performance impact compared to a BIT - is there, considering I need the same length of array to start with? I have defined an array in the same way based on the length of my JText Area:
int[] pC = new int[myArea.getText().length()];
I then search for my regions and whenever I find a region I set the appropriate position to 1 in my array:
for (int i = m.start(); i < m.end(); i++) {
pC[i] = 1;
}
I can then do a simple check against position Z using the following syntax:
if (pC[Z] == 0) {
// OUTSIDE REGION
}
else {
// INSIDE REGION
}

Categories

Resources