I'm working with recursion trying to become better at with it. My current activity is trying to program a recursive method that generates the maximum number of events one could schedule. Heres my method so far:
public int maxEvents(int n, int[] Start) {
if(n<=0) return 0;
if(n==1) return 1;
else return maxEvents(n-1, Start) + maxEvents(Start[n]-1, Start);
}
Basically my main method passes maxEvents an int n, which is the last Event. So say I have 4 events (1-4) then n would be 4. The next part is an array who's value at the index is the time the event starts, and the index itself is when the event ends.
The preconditions are:
n >= 0
days and conventions go from 1 to n
Event n ends at (and includes) day n and begins at Start[n]
Begin[0] is unused
For all i from 1 to n, Begin[i] <= i ( Convention i can't have a later beginning day than ending day, of course.)
At the end my method is supposed to return:
The maximum number of conventions you can host if you must select only from conventions 1 through n. (This set is empty if n = 0)
Some example input / outputs:
n = 3 Begin[1]=1 Begin[2]=1 Begin[3]=3
maxEvents=2
Or:
n = 5 Begin[1]=1 Begin[2]=1 Begin[3]=2 Begin[4]=3 Begin[5]=4
maxEvents=3
My two recursive calls should count the maximum number without inviting n, you can then chose from 1 to n-1. And count the maximum number inviting n, noting that Begin[n]-1 is the last convention that does not conflict with the beginning of convention n. Then I could take the max of the two, and return that.
I've tried using different if statements, saying something like:
if("recursion call 1">"recursion call 2"){
return "recursion call 1";
}
And using something like "maxEvents(Start[n]-1, Start)" as one of my recursive calls (like used in my above code) however its not returning the correct values, like the ones I listed above. All in all I'm having trouble with the concept of recursion, and I know something is wrong with my recursive calls, so if someone could point me in the right direction that'd be great. Thanks!
Does this work?
return Math.max(maxEvents(n-1, Start), 1 + maxEvents(Start[n]-1, Start))
The idea is that you are splitting into two mutually exclusive cases: one where the nth event is not included and another where nth event is included. Out of the two, you have to select the bigger. So adding the two is not correct - taking the max is the right way. But you have to also add a 1 to the second option to account for including the nth event.
Related
I am looking at the LeetCode problem 2134. Minimum Swaps to Group All 1's Together II:
A swap is defined as taking two distinct positions in an array and swapping the values in them.
A circular array is defined as an array where we consider the first element and the last element to be adjacent.
Given a binary circular array nums, return the minimum number of swaps required to group all 1's present in the array together at any location.
I am trying to study how other people came up with solutions of their own. I came across this particular one, but I don't understand the logic:
class Solution {
public int minSwaps(int[] nums) {
// number of ones
int cntones=Arrays.stream(nums).sum();
// worst case answer
int rslt=nums.length;
// position lft and figure better value for min/rslt
int holes = 0;
for(int i=0;i<cntones;i++) {
if(nums[i]==0)
holes++;
}
// better value for rslt from lft to rgt
// up to index of cntones.
rslt = Math.min(rslt, holes);
// they have a test case with one element
// and that trips up if you dont do modulo
int rgt=cntones % nums.length;
for(int lft=0;lft<nums.length;lft++) {
rslt=Math.min(rslt,holes);
if(nums[lft]!=nums[rgt])
if(nums[rgt]==1)
holes--;
else
holes++;
rgt=(rgt+1)%nums.length;
}
return rslt;
}
}
Why is the worst case, the length of the input array?
I'm thinking wait, wouldn't the worst case be something like [0,1,0,1,0,1...] where 0's and 1's are alternating? Can you give me an example?
I suppose #of holes can potentially be a possible solution in some cases, from counting 0's in a fixed length (the number of total 1's) of a window but because I do not understand the worst case, rslt from question #1, below line stumps me as well.
// better value for rslt from lft to rgt
// up to index of cntones.
rslt = Math.min(rslt, holes);
About the modulo below, I don't think cntones can ever be bigger than nums.length, in turn which will result in 0 all the time? I'm thinking for the case with one element, you'd have to check whether that one element is 0 or 1. How does below line cover that edge case?
// they have a test case with one element
// and that trips up if you dont do modulo
int rgt=cntones % nums.length;
Due to #1~#3 the last for loop makes no sense to me...
Why is the worst case, the length of the input array?
First note that a swap is only useful when it swaps a 0 with 1. Secondly, it makes no sense to swap the same digit a second time, as the result of such double swap could have been achieved with a single swap. So we can say that an upper limit for the number of swaps is the number of 0-digits or number of 1-digits (which ever is the least). In fact, this is an overestimation, because at least one 1-digit should be able to stay unmoved. But let's ignore that for now. To reach that worst case, there should be as many 1 as 0 digits, so then we have half of the length as worst case. Of course, by initialising with a value that is greater than that (like the length) we do no harm.
The example of alternating digits would be resolved by keeping half of those 1-digits unmoved, and moving the remaining 1-digits in the holes between them. So that means we have a number of swaps that is equal to about one fourth of the length of the array.
below line stumps me as well.
rslt = Math.min(rslt, holes);
As you said, there is a window moving over the circular array, which represents the final situation where all 1-digits should end up. So it sets the target to work towards. Obviously, the 1-digits that are already within that window don't need to be swapped. Each 0-digit inside that window has to be swapped with a 1-digit that is currently outside that window. Doing that will reach the target, and so the number of swaps for reaching that particular target window is equal to the number of holes (0-digits) inside that window.
As that exercise is done for each possible window, we are interested to find the best position of the window, i.e. the one where the number of holes (swaps) is minimised. That is what this line of code is doing. rslt is the minimum "so far" and holes is the fresh value we have for the current window. If that is less, then rslt should be updated to it. That's what happens in this statement.
About the modulo below, I don't think cntones can ever be bigger than nums.length, in turn which will result in 0 all the time? I'm thinking for the case with one element, you'd have to check whether that one element is 0 or 1. How does below line cover that edge case?
int rgt=cntones % nums.length;
That modulo only serves for the case that cntones is equal to nums.length. You are right that it will never exceed it. But the case where it is equal is possible (when the input only has 1-digits). And as rgt is going to be used as an index, it should not be equal to nums.length as that is an undefined slot in the array.
Due to #1~#3 the last for loop makes no sense to me...
It should be clear from the above details. That loop moves the window with one step at a time, and keeps the variable holes updated incrementally. Of course, we could have decided to count the number of holes from scratch in each window, but that would be a waste of time. As we go from one window to the next, we only lose one digit on the left and gain one on the right, so we can just update holes with that information and know how many holes there are in the current window -- the one that starts at lft and runs (circular) to rgt. In case the digit that we lose at the left is the same as the one we gain at the right, we obviously didn't change the number of holes. Where they are different, we either win or lose one hole in comparison with the previous window.
I saw this method in a book, to do binary search, but I can't understand how it is working no matter how I try. Can someone explain to me exactly how it is working?
the book's explanation did not help :
The idea is to make jumps and slow the speed when we get closer to the
target element.
The variables k and b contain the position in the array and the jump
length. If the array contains the element x , the position of x will
be in the variable k after the search. The time complexity of the
algorithm is O (log n ), because the code in the while loop is
performed at most twice for each jump length.
what I don't get is that how is k iterating in the array? How can we make sure that it will not jump over the target's index? I tried tracing some runs of this program with sample values but couldn't figure out the pattern that k is following to find whether target x exists in the array or not.
int k = 1;
for (int b = n/2; b >= 1; b /= 2) {
while (k+b <= n && t[k+b] <= x) k += b;
}
if (t[k] == x) {} // x was found at index k
note: I do understand clearly the "common binary search algorithm" (the one that uses start, middle, and end indices )
b are the length of the jumps of your current position. As you can see, b starts as n/2 and is divided by 2 at each step up until it reaches 1.
Now, For each b, remember that b is divided by 2 at each step in the for loop, we run a while loop where we add b to to our current position, which is k. We add b to k checking for 2 conditions: k+b is less than n (to make sure we don't go out of bounds), and t[k+b] is less than x, which we are searching.
This effectively means that for each b, we add b to k up until where it would go over the value we are seeking. At this point, the while loop breaks and we divide b to approach slower to the target hoping we don't go over it.
The final b is just one, to make sure we don't miss x if it is just the next element after the position of k.
Look at it this way, a car is racing towards a goal. At first the car is going maximum speed, as it nears the target, it gradually decelerates up until it reaches the target.
The difference with traditional binary search, which makes it a little counter intuitive, is that in traditional binary search, we go over the target and then come back and go over again and in each iteration we decrease the steps that we take back and forth. In this algorithm, we only go forwards (never over the target), but we continuously decrease the length of the steps by dividing b.
I need to find algorithm which will find the longest seqeunce of element in one
dimension array.
For example:
int[] myArr={1,1,1,3,4,5,5,5,5,5,3,3,4,3,3}
solution will be 5 because sequnece of 5 is the longest.
This is my solution of the problem:
static int findSequence(int [] arr, int arrLength){
int frequency=1;
int bestNumber=arr[0];
int bestFrequency=0;
for(int n=1;n<arrLength;n++){
if(arr[n]!=arr[n-1]){
if(frequency>bestFrequency){
bestNumber=arr[n-1];
bestFrequency=frequency;
}
frequency=1;
}else {
frequency++;
}
}
if( frequency>bestFrequency){
bestNumber=arr[arrLength-1];
bestFrequency=frequency;
}
return bestNumber;
}
but I'm not satisfied.May be some one know more effective solution?
You can skip the some number in the array in the following pattern:
Maintain a integer jump_count to maintain the number of elements to skip (which will be bestFrequency/2). The divisor 2 can be changed according to the data set. Update the jump_count every time you update the bestFrequency.
Now, after every jump
If previous element is not equal to current element and frequency <= jump_count, then scan backwards from current element to find number of duplicates and update the frequency.
e.g. 2 2 2 2 3 3 and frequency = 0 (bold are previous and current elements), then scan backwards to find number of 3's and update the frequency = 2
If previous element is not equal to current element and frequency > jump_count, scan for scan for every element to update the frequency and update the bestFrequency if needed.
e.g. 2 2 2 2 2 3 3 and frequency = 1 (bold are previous and current elements), scan for number of 2's in this jump and update the frequency = 1 + 4. Now, frequency < bestFrequency, scan backwards to find number of 3's and update the frequency = 2.
If previous element = current element, scan the jump to make sure it is continuous sequence. If yes, update the frequency to frequency + jump_count, else consider this as the same case as step 2.
Here, we will consider two examples:
a) 2 2 2 2 2 2 (bold are previous and current elements), check if the jump contains all 2's. Yes in this case, so add the jump_count to frequency.
b) 2 2 2 2 3 2 (bold are previous and current elements), check if the jump contains all the 2's. No in this case, so considering this as in step 2. So, scan for number of 2's in this jump and update the frequency = 1 + 4. Now, frequency < bestFrequency, scan backwards to find number of 2's(from the current element) and update the frequency = 1.
Optimization: You can save some loops in many cases.
P.S. Since this is my first answer, I hope I am able to convey myself.
Try this:
public static void longestSequence(int[] a) {
int count = 1, max = 1;
for (int i = 1; i < a.length; i++) {
if (a[i] == a[i - 1]) {
count++;
} else {
if (count > max) {
max = count;
}
count = 1;
}
}
if (count> max)
System.out.println(count);
else
System.out.println(max);
}
Your algorithm is pretty good.
It touches each array element (except the last) only once. This puts it at O(n) runtime which for this problem seems like the best worst case runtime you can get and is a pretty good worst case runtime as far as algorithms go.
One possible suggestion is when you find a new bestFrequency and n+bestFrequency > arrayLength you can break out of the loops. This is because you know a longer sequence cannot be found.
The only optimization that seems possible is:
for(int n=1;n<arrLength && frequency + (arrLength - n) >= bestFrequency;n++){
because you don't need to search any further one you can't possible exceed the best frequency with the number of elements remaining (probably possible to simplify that even further given a little more thought).
But as others point out, you're doing a O(n) search on n elements for a sequence - there's really no more efficient algorithm available.
I was thinking this must be an O(n) problem, but now I'm wondering if it doesn't have to be, that you could potentially make it O(log n) using a binary search (I don't think what #BlackJack posted actually works quite right, but it was inspiring):
Was thinking something like keep track of first, last element (in a block, probably a recursive algorithm). Do a binary split (so middle element to start). If it matches either first or last, you possibly have a run of at least that length. Check if the total length could exceed the current known max run. If so, continue, if not break.
Then repeat the process - do a binary split of one of those halves to see if the middle item matches. Repeat this process, recursing up and down to get the maximum length of a single run within a branch. Stop searching a branch when it can't possibly exceed the maximum run length.
I think this still comes out to be an O(n) algorithm because the worth-case is still searching every single element (consider a max length of 1 or 2). But you limit to checking each item once, and you search into the most-likely longest branches first (based on start/middle/end matches), it could potentially skip some fairly long runs. A breadth-first rather than depth-first search would also help.
I wrote a code for filling the prefix table for KMP. It is small variation of this algorithm. I'm unable to convince myself that this algorithm/implementation runs in O(n) time. I have hard time figuring out the second recursive call affect on the total run time. Any help?
public void fillFailTable(int[] failTable,String p){
failTable[failTable.length-1] = preLength(failTable,p);
}
private int preLength(int[] failTable,String s){
if(s.length() == 1){
return 0;
}
int n = s.length();
int k = preLength(failTable,s.substring(0,n-1));
failTable[n-2] = k;
if(s.charAt(k) == s.charAt(n-1)){
return k+1;
}else{
return preLength(failTable,s.substring(n-1-k));
}
}
It's actually pretty interesting (I'm still wondering why no one smarter than me answered this yet). Please take this explanation with a grain of salt as I'm not 100% sure this is even close to being correct (although I can tell you for 100% that this method runs in O(n) since that's what they told me at the University years ago but they didn't bother explaining it though, d'uh, so I had to come up with it on my own).
Ok so let's start with a very basic example of s.length = 2. Two things to mention beforehand:
during each example lets only worry about the worst case scenarion, since we're interested in Big Oh, meaning we enter the second preLength() method.
we can observe, when looking for the Big Oh, that "k" (and the values returned by preLength()) in this code will always be 0, which you will notice in the images below and which is really important.
s.length == 2
We first enter the first preLength() method (lets call it *), which is now invoked with s.length = 1 and return immediately with a 0. Now since we're considering only the worst case scenario (meaning s.charAt(k) != s.charAt(n-1)) we enter the second preLength() with also a string of length = 1 (since n=2 and k=0). This one also returns a 0 immediately to our *. This ends our method invocation. In total we had 3 method invocations. Our * and two preLength(). Here's an image:
s.length == 3
Now lets look at an example with a starting s.length = 3. As you can notice we immediately invoke a preLength() with s.length = 2 and, from our previous example, we know that this one need 3 method invocations. Now we need to remember that when the method preLength(2) returns this time it returns to our native preLength(3) which will now invoke again preLength(2) (the one in the else) which will again need 3 method invocations. So in total we need 2*3+1 method invocations. This gives us 7. Again, here's an image (a circle is an invocation of preLength with a string of the length shown in the circle):
Conclusions
Now as you can see all those method invocations are symmetrical - and that is because our k is always equal to 0 which means that the second preLengt() will be invoked with a string of the same size as the first one - and we can see how many of them we will need for s.length = m when we know how many of them we need for m-1 since f(m) = 2*f(m-1)+1 where f(m) is the function telling us how many method invocations we need to compute the table for a string of size m. This works since as I said before the method invocations are symmetrical (that's because in worst case k=0 always and preLenght() always return 0, hence the 2* and we need to add 1 method invocation, the first one we ever invoke).
So basically with each incrementation of our input (size of m) the computational time grows 2 times plus one (2*m+1) which to my understanding means that this method is, in worst case, O(n).
As I said please do take this with a grain of salt but I hope this makes some sense :)
I have a function in java which is written with a recursive algorithm that needs to be written in Iterative form. The thing is that I dont know where to start in wrapping my mind around a new algorithm for this. This is an assignment I am working on.
Consider the following computational problem:
Suppose you work as a consultant and you have a sequence of n potential consulting jobs that pay A[0],A[1],..,A[n-1] dollars, respectively (so job 0 pays A[0] dollars, job 1 pays A[1] dollars, etc.).
Also, job i starts on day i (i = 0 ; : : : ; n 1 ).
However, each job requires 2 days, so you cannot perform any two consecutive jobs. The goal is to determine the maximum amount of money, denoted by F(n) ; you can earn from a valid job schedule selected from the n jobs A[0] through A[n-1]
:
As an example, consider the following input array:
0 1 2 3 4 5
A 5 6 8 6 2 4
An optimal schedule is to do jobs 0 ; 2 ; and 5 ; for which the amount of money
earned, F(6) = A[0] + A [2] + A [5] = 17 ; is as large as possible. Notice that this
is a valid schedule, as no two consecutive jobs are included.
My function for the recursive version that solves this is as follows:
public static int jobScheduleRecursive(int[] A, int n)
{
n = A.length;
if(n == 0){return 0;}
else if(n == 1){return A[0];}
else if(n >= 2){return max(jobScheduleRecursive(A, (n-1)), (A[n-1])
+ jobScheduleRecursive(A, n-2));}
else return -1;
}
To sum up, I have to come up with an iterative algorithm that does this job. The only problem is that i have no idea how to proceed. I would appreciate any advice to lead me in the right direction.
sometimes, iterative solutions for a known recursive solution to problems isn't straight forward as the recursive solution. The easiest way to achieve iterative solution is to use - Dynamic Programming basically what you want is to create a temporary array that holds the solution to all sub-problems in the way. to achieve that, create a dynamically allocated array in the size of your input. and if for instance your recursive function is int foo(int a)
fill the array with the solutions to 1..n, where n is the input for your original problem.
change the algorithm, that instead of calling itself recursivelly, it will check if the solution for the sub-problem allready exists in the array, if not, it fills it up. that way a sub-problem won't compute numerus times, but only once.