Sorted Array Distinct Values Sum to Target - java

I am currently working on this coding problem for class.
Given a sorted array of n distinct values as well as a target value T, determine in O(n) time whether or not there exist two distinct values in the array that sum to T. (For example, if the array contained 3, 5, 6, 7, and 9 and T = 14, then the method you are to write should return true, since 5+9 = 14. It should return false if for the same array of values T = 17.)
So, initially, I just wrote the problem with a nested linear search approach which obviously results in a O(n^2) runtime to establish a baseline to simplify from, however, I have only been able to, so far, simplify it to O(n log(n)). I did this by creating a new array made up of the differences of the Target - array[i] and then comparing the new array to the original array using a binary search nested within a loop that linearly goes up the new array.
I am not asking for an answer but rather a hint at where to look to simplify my code. I feel like the fact that the array is sorted is important in getting it down to O(n) but not sure how to go about doing it.
Thanks for your time!

Imagine you have two pointers (s, e) wich set on start and end of you array.
If you will move them in opposite direction (with specific algorithm) and look at the summ of elements you will see that moving one pointer increase summ and moving other decrease.
Onli thing you need is find balance.
If it doesnt help. Ask for next tip.

Some tips/steps:
1 - Start the iteration by the array[i], which is the nearest lower value from T
2 - Move another pointer to the array[0]
3 - Sum both values and compare with T
4 - If bigger or if lower, do appropriate moving in the pointers and repeat the step 3

A Hint:
Something like Binary Search, start with middle (compare with middle)
we have startindex = 0, endindex = N-1
while(some condition){
middleindex = endindex - startindex / 2, middle = array[middleindex]
if T - array[middleindex] > middle, startindex = middleindex
if T - array[middleindex] < middle, endindex = middleindex
}
It will do the task in O(log(n)) :D

Related

Dynamic Programming - Rod Cutting Problem with maximum cuts and actual solution

So I'm trying to write code for a modified version of the rod cutting problem. The link gives a good intuition of the problem. However, I want to modify the code to not only actually return the solution, i.e. what cuts give the optimal solution, but also limit the number of cuts to a maximum of k.
For proof of concept, I'm trying to create an algorithm to achieve this. The following is what I have so far, I think it successfully returns the actual solution, however, I can't figure out how to limit the maximum to k.
let r[0..n] be a new array
r[0] = 0
for j = 1 to n
q = -1
for i = 1 to j
for k = 0 to n-1
q = Math.max(q[n][k], p[i] + q[n-i-1][k-1]);
r[j] = q
return r[n]
Please do not provide with actual code in your answers, I want to implement that myself, I just need help tweaking my algorithm to give the correct solution.
Update 1: I am already able to find optimal solution for a maximum of k cuts by adding a second dimension to my array. This is shown in the above code.
As you say, you already have the optimal solution, this answer includes only how to retrace the exact solution (cuts made at each step).
Store the candidate cut for length = n and maximum cuts = k
For this, you simply need a 2-d array (say, visit[n][k]) to store the cut made that gets the maximum solution to q[n][k]. In terms of pseudo code and recurrence relations, it will look like the following.
for each value of i:
q[n][k] = q[n][k-1]
visit[n][k] = -1
if q[n][k] < p[i] + q[n-i-1][k-1]:
q[n][k] = p[i] + q[n-i-1][k-1]
visit[n][k] = i
Explanation
It is possible that we don't have a cut that maximizes the solution. In this case, we initialize visit[n][k] = -1.
Every time, we have a candidate to cut the rod of length n at length=i+1, ie. we could get a better price by a cut, we will store the respective cut in another 2-d array.
Reconstruct the solution
Using this 2-d array (visit[n][k]), to back trace the exact cuts, you can use the following pseudo code (I am deliberately avoiding code since you mentioned you don't need it).
cuts = []
while k > 0:
i = visit[n][k]
if i != -1
// If there is a cut
cuts.push(i + 1)
n = n - i - 1
k = k - 1
Explanation
We iterate from k to 0.
Every time, when visit[n][k] is not -1, ie. it is optimal to cut somewhere, we reassign n after making the cut, ie. n = n - i - 1 and store the resultant cut in the array cuts.
Finally, cuts will contain the exact cuts that led to the optimal solution.
Please note that the pseudo code present in your question is slightly incorrect in terms of variables used in the recurrence relation. q is used both to store the DP 2-d array as well as an integer -1. j is not used in the bottom-up DP at all and is replaced with constant n. q[j][k] is uninitialized. However, the general idea is correct.

Confusion on quicksort that takes logarithmic space

If only the smaller partitioned array is being called how is the larger one sorted? I only see code to change the position of b if done recursively (QS called in if and else statement).
public static void QS(int[] b, int h, int k) {
int h1= h; int k1= k;
// invariant b[h..k] is sorted if b[h1..k1] is sorted
while (b[h1..k1] has more than 1 element) {
int j= partition(b, h1, k1);
// b[h1..j-1] <= b[j] <= b[j+1..k1]
if (b[h1..j-1] smaller than b[j+1..k1])
QS(b, h, j-1); h1= j+1;
else
QS(b, j+1, k1); k1= j-1;
}
}
That is some hard to read psuedo-code. This might be a bit easier to understand:
QuickSort(b[], low, hi)
while the range low..hi contains more than 1 element
1: Pick a random pivot 'j' from the array
2: Re-order the array so that all elements less than the pivot are in
b[low..j-1], and all elements greater than the pivot are in b[j+1..hi]
3: Call quicksort on the side with less elements, and update the range to
exclude the sorted side
Roughly half of the values will be less than the pivot, and half of the values will be greater than the pivot. This means that after step 3, the size of the range low..hi has roughly halved. Thus, it takes log|N| iterations before the range contains only one element.
It's hard to explain this bit, but see how step 3 only calls QuickSort on one half of the array? It's because the remainder of the while-loop sorts the other half. The function could easily be re-written as the following:
QuickSort(b[], low, hi)
if the range low..hi contains more than 1 element
1: Pick a random pivot 'j' from the array
2: Re-order the array so that all elements less than the pivot are in
b[low..j-1], and all elements greater than the pivot are in b[j+1..hi]
3: Call quicksort on both sides
The while-loop has been replaced by an if statement and a second recursive call. I hope from here that you can see the complexity is roughly N log|N|.
Edit
So how does the while-loop sort the remaining elements? After step 3, the range has been updated to exclude the smaller half, because we just sorted it with a call to QuickSort. This means that the range now only contains the larger half - the unsorted elements. So we repeat steps 1 - 3 on these unsorted elements, and update the range again.
The number of unsorted elements gets smaller and smaller with every iteration, and eventually we will be left with only one unsorted element. But of course, one element on its own is sorted, so at this point we know we have sorted every element in the array.
Note after the recursive call to QS, h1 is is updated if b[h1..] was smaller than b[j+1..] and k1 is updated if if b[h1..] was greater or equal to b[j+1..] .
There's a bug in the code, the first call after the if should be QS(b, h1, j-1);
Logarithmic space usage is referring to the stack space used by quicksort due to recursion. In the example code, only the smaller partition is sorted with a recursive call, then the code loops back to split up the larger partition into two parts, and again, only use a recursive call for the smaller part of the now split up larger partition.
Link to articles:
http://en.wikipedia.org/wiki/Quicksort#Optimizations
http://blogs.msdn.microsoft.com/devdev/2006/01/18/efficient-selection-and-partial-sorting-based-on-quicksort
I'm not sure about the reference to tail recursion, since the code includes an actual loop instead of using tail recursion. Tail recursion would look like a recursive call on the last line to be executed in a function, where a compiler can optimize it into a loop.

algorithm for finding longest sequence of the same element in 1D array-looking for better solution

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.

Find all differences in an array in O(n)

Question: Given a sorted array A find all possible difference of elements from A.
My solution:
for (int i=0; i<n-1; ++i) {
for (int j=i+1; j<n; ++j) {
System.out.println(Math.abs(ai-aj));
}
}
Sure, it's O(n^2), but I don't over count things at all. I looked online and I found this: http://www.careercup.com/question?id=9111881. It says you can't do better, but at an interview I was told you can do O(n). Which is right?
A first thought is that you aren't using the fact that the array is sorted. Let's assume it's in increasing order (decreasing can be handled analogously).
We can also use the fact that the differences telescope (i>j):
a_i - a_j = (a_i - a_(i-1)) + (a_(i-1) - a_(i-2)) + ... + (a_(j+1) - a_j)
Now build a new sequence, call it s, that has the simple difference, meaning (a_i - a_(i-1)). This takes only one pass (O(n)) to do, and you may as well skip over repeats, meaning skip a_i if a_i = a_(i+1).
All possible differences a_i-a_j with i>j are of the form s_i + s_(i+1) + ... + s_(j+1). So maybe if you count that as having found them, then you did it in O(n) time. To print them, however, may take as many as n(n-1)/2 calls, and that's definitely O(n^2).
For example for an array with the elements {21, 22, ..., 2n} there are n⋅(n-1)/2 possible differences, and no two of them are equal. So there are O(n2) differences.
Since you have to enumerate all of them, you also need at least O(n2) time.
sorted or unsorted doesn't matter, if you have to calculate each difference there is no way to do it in less then n^2,
the question was asked wrong, or you just do O(n) and then print 42 the other N times :D
You can get another counter-example by assuming the array contents are random integers before sorting. Then the chance that two differences, Ai - Aj vs Ak - Al, or even Ai - Aj vs Aj - Ak, are the same is too small for there to be only O(n) distinct differences Ai - Aj.
Given that, the question to your interviewer is to explain the special circumstances that allow an O(n) solution. One possibility is that the array values are all numbers in the range 0..n, because in this case the maximum absolute difference is only n.
I can do this in O(n lg n) but not O(n). Represent the array contents by an array of size n+1 with element i set to 1 where there is a value i in the array. Then use FFT to convolve the array with itself - there is a difference Ai - Aj = k where the kth element of the convolution is non-zero.
If the interviewer is fond of theoretical games, perhaps he was thinking of using a table of inputs and results? Any problem with a limit on the size of the input, and that has a known solution, can be solved by table lookup. Given that you have first created and stored that table, which might be large.
So if the array size is limited, the problem can be solved by table lookup, which (given some assumptions) can even be done in constant time. Granted, even for a maximum array size of two (assuming 32-bit integers) the table will not fit in a normal computer's memory, or on the disks. For larger max sizes of the array, you're into "won't fit in the known universe" size. But, theoretically, it can be done.
(But in reality, I think that Jens Gustedt's comment is more likely.)
Yes you can surely do that its a little tricky method.
to find differances in O(n) you will need to use BitSet(C++) or any similar Data Structure in respective language.
Initialize two bitset say A and B
You can do as follows:
For each iteration through array:
1--store consecutive differance in BitSet A
2--LeftShift B
3--store consecutive differance in BitSet B
4--take A=A or B
for example I have given code-
Here N is Size of array
for (int i=1;i<N;i++){
int diff = arr[i]-arr[i-1];
A[diff]=1;
B<<=diff;
B[diff]=1;
A=A | B;
}
Bits in A which are 1 will be the differances.
First of all the array need to be sorted
lets think a sorted array ar = {1,2,3,4}
so what we were doing at the O(n^2)
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++) sum+=abs(ar[i]-ar[j]);
if we do the operations here elaborately then it will look like below
when i = 0 | sum = sum + {(2-1)+(3-1)+(4-1)}
when i = 1 | sum = sum + {(3-2)+(4-2)}
when i = 2 | sum = sum + {(4-3)}
if we write them all
sum = ( -1-1-1) + (2+ -2-2) + (3+3 -3) + (4+4+4 )
we can see that
the number at index 0 is added to the sum for 0 time and substracted from the sum for 3 time.
the number at index 1 is added to the sum for 1 time and substracted from the sum for 2 time.
the number at index 2 is added to the sum for 2 time and substracted from the sum for 1 time.
the number at index 3 is added to the sum for 3 time and substracted from the sum for 0 time.
so for we can say that,
the number at index i will be added to the sum for i time
and will be substracted from the sum for (n-i)-1 time
Then the generalized expression for
each element will be
sum = sum + (i*a[i]) – ((n-i)-1)*a[i];

Please help me solve my Java homework about arrays

Problem Statement:
Given an array of ints, compute if the array contains somewhere a value followed in the array by that value times 10. We'll use the convention of considering only the part of the array that begins at the given index.The initial call will pass in index as 0.
Examples:
public boolean array220(int[] nums, int index)
array220({1, 2, 20}, 0) → true
array220({3, 30}, 0) → true
array220({3}, 0) → false**
I'm stuck with the problem with no approach to solve it.
for (int i = index; i < nums.length - 1; i++)
if (nums[i] * 10 == nums[i + 1]) return true;
return false;
I'll give you some psuedo code to work with.
Let `nums` be my array
Let `i` be the starting index
Let `index` be `i + 1`
for all indices < array's length, iterate
Let currNum be `array[index - 1]`
if currNum times 10 equals `array[index]`
return true
increment index
return false because we found no numbers that we true
I'm not going to give you the answer as a Java program, since a number of folks have already done that.
When in doubt, try writing out the program in English (or any other native tongue). If you can't write it out in complete detail, write out what you can, and then refine in pieces.
Given an array of ints, compute if the array contains somewhere a value followed in the array by that value times 10. We'll use the convention of considering only the part of the array that begins at the given index.The initial call will pass in index as 0.
What do we know here? We have an array and a starting index. So, what do you want to do? Maybe that's a bit complicated, so if we were doing it by hand, how would you start?
Look at the first element of the array (where "first" is the starting index)
Look at the next element of the array and divide it by 10
Look at the results from steps #1 and #2. Are they the same?
If they are, return true
If they are not, start back again at step #1, but look at the following elements instead
Then refine that further:
Set the current index to be the starting index
For each element of the array, from the current index through the end:
Get the following element and divide by 10
Are the two numbers equal? If so, we're done, return true
If not, increment the current index and repeat
You may notice that there is a small issue with step #2: You don't want to loop all the way to the end. Because if you do that, there won't be any "next" element to compare it to. So really you want to loop to the second-to-last element.
Continue refining. At some point you can translate directly to Java or whatever programming language you want. (If you can't do this last step, you need to add an additional step 0: Learn the programming language first)
Recursive answer just for the hell of it... also I wouldn't post this is there weren't already valid answers. Make an attempt and post what you tried.
public boolean array220(int[] nums, int index){
if(index >= nums.length - 1)
return false;
if(nums[index] * 10 == nums[index + 1]){
return true;
} else {
return array220(nums, ++index);
}
}

Categories