I'm new at algorithms and want to know how to solve this task. A detailed Java solution is desirable.
You have been given an integer n≥2 and an integer array A[0..n−1] which is sorted in
nondecreasing order . All numbers repeat 1 time but one number repeats 2 times, how do you find the number that repeat 2 times. Using data structures and built-in functions was not allowed. Complexity of algorithm should be O(lg(n))
You can use a custom binary search algorithm.
We can observe that if there would be only values that repeated once (which occur twice), then the size of the array is even, and we have for each even index i: A[i] == A[i+1].
Since there is exactly one triplet, the array's size is odd, and so if we find an even index i for which A[i] == A[i+1] we know that the triplet did not occur at the left side of i. If however A[i] != A[i+1], then we are sure the triplet occurred at the left side of i.
This is all we need to perform a binary search. We should just make sure we always make our checks at even indices.
Here is an implementation in JavaScript:
function binarySearchTriplet(arr) {
let lo = 0, hi = arr.length - 1; // even
while (lo < hi) {
// Take mid, but force it to be even
mid = (lo + hi) >> 2 << 1;
if (arr[mid] === arr[mid+1]) {
lo = mid + 2;
} else {
hi = mid;
}
}
return arr[lo];
}
let arr = [1,1,4,4,4,5,5,7,7,2,2,6,6,8,8];
console.log(binarySearchTriplet(arr)); // 4
Related
Suppose you have a method subArrayLeftShift(a,i) which shifts left the sub array a[i,...,n-1] when n is the array length. That means that the elements a[i+1],...,a[n-1] are moving one place to the left, and the original a[i] will become the last one.
More formally, here is the function implementation:
public static void subArrayLeftShift(int[] a, int i){
if (a.length == 0) return;
int last = a.length - 1;
int insertToLast = a[i];
for (; i < last; i++){
a[i] = a[i + 1];
}
a[last] = insertToLast;
}
Now for the question: implement a function that receives an unsorted array, and returns the minimal number of calls to subArrayLeftShift for sorting the array.
In the interview I couldnt find the way to do it. I succeed to find the minimal number of calls for every example I wrote for intuition, but couldn't find a way for generalizing it.
Do you know how to solve it?
I propose the following algorithm to solve the problem:
Find the minimum number in the array that is not sorted ( has a smaller number on the right in the array). Let this number be x.
Count how many numbers in the array are greater than the previously found number x. Let this number be y.
Since for each call to the function, the unsorted number will end up at the last position, the optimum strategy is to call the function for each unsorted number in increasing order. Using what was found previously we start with x. We continue with the next unsorted number bigger than x, because in this way, it will end up on the right of x, hence it will be sorted. Continue in the same fashion. How much? How many bigger number than x we have? Well, that's y. So as a total, the number of calls to the function is 1 + y.
public static int minimumCalls(int[] a) {
int minCalls = 0;
for (int i = 0; i < a.length - 1; i++) {
for (int j = i+1; j < a.length; j++) {
if (a[i] > a[j]) {
minCalls++;
break;
}
}
}
return minCalls;
}
The idea behind my thinking is that you must invoke the method once whenever there exists in the SubArray any value less than the current i. The name of the method subArrayShiftLeft, i feel, is designed to throw you off and drag your attention away from thinking of this easily.
If there's any values less than the current one further on in the array, just invoke the method.
It's much easier to think of this as moving a single larger value to the end of the array than trying to shift the smaller ones to the left.
This question already has answers here:
O(log n) algorithm to find best insert position in sorted array
(7 answers)
Closed 5 years ago.
I could use your help on this. I am trying to create a method that would do a binary search for a position where a new element would be inserted, use a natural order compare method in the process, the code that I have written is wrong obviously, I'm new to writing algorithims and just not sure how to implement this. so for example
int[] list = {10,15,20,25,30};
and I want to insert 17, I have another method that would add it but I need the position it would go in by doing a binary search and compare method assuming natural order. Thanks in advance for all your help. This is what I have so far but when I try and insert 53 it gives position 4 instead of 5. Any suggestions?
public int getIndex(E element) {
E e = (E)element;
int low = 0;
int high = this.size;
int mid = 0;
if(size == 0) {
return 0;
}
while (low <= high) {
mid = (high + low) / 2;
if (list[mid]== null) {
return mid;
}
if (compare(e, list[mid]) < 0) {
high = mid - 1;
} else if (compare(e, list[mid]) > 0) {
low = mid + 1;
} else {
return (int) list[mid];
}
}
return mid;
}
Because you haven't posted any code, here's a hint:
Start from the middle index of the array. In your case, this will be index 2, holding 20.
We can see that 20 is larger than the number you wish to insert (17), so we navigate to the middle index of the lower half of the array ({10, 15} - in this case, index 1).
Because there are only 2 elements, we check the value of the higher element first (15).
17 is greater than 15, so we would want to navigate to the next, higher sub-array, but it's empty!
This means that you're ready to insert your value (17) at the index right after 15 (in this case, 17 would be placed at index 2).
Keep in mind that, for a binary search to work, the array needs to be sorted. It isn't in your example.
This is a school assignment, however, the requirement was that the program be "implemented with maximum performance" - which is vague to my taste, because I don't know would memory outweigh speed or not etc. But what I'm looking for is whether there is a "tricky" way to solve the problem by doing some smart manipulation on the input data.
So, here's the problem: consider you have two arrays, A and B, write a function that returns 1 if there is such integer in B, that equals to the sum of any two subsequent elements of A.
Below is my writeup. Note that I didn't use Hashmap<Integer> because I considered the memory required for the speedup to be a disadvantage strong enough to live with the O(n * m) speed as my worst case instead of O(n).
public static int arrayContainsSum(int[] a, int[] b)
{
int offsetA = a.length - 1;
int offsetB = offsetA;
int index = b.length - 1;
int result = 0;
int tested;
while (index >= 0)
{
if (offsetA > 0) a[offsetA] += a[--offsetA];
else if (offsetA == 0) // This has a danger of overflowing the int
a[offsetA--] = multiply(a);
tested = b[index];
if ((offsetA < 0 && tested != 0 && a[0] % tested != 0) ||
offsetB == 0)
{
// No point to test this element as it doesn't
//divide the product of sums
offsetB = a.length - 1;
index--;
}
if (tested == a[offsetB--])
{
result = 1;
break;
}
}
return result;
}
private static int multiply(int[] input)
{
int accumulator = input.length > 0 ? 1 : 0;
for (int i : input)
if (i != 0) accumulator *= i;
return accumulator;
}
There are some things I'm not concerned with: integer overflow (which might happen as a result of multiplication). I assumed array.length to be as fast as reading from local variable.
But, again, my question is rather "wasn't it possible to solve this problem analytically?" which would mean better efficiency?
PS. The problem doesn't mention if arrays contain only unique members - no limitations on that. I also think it would be possible to optimize (if I detect such case) by sorting a so that in case that the b[x] is smaller than the smallest element in a or greater then the largest element in a, it would save some lookups - but, again, this would come on expense of increased complexity, possibly, not entirely justified.
public static int arrayContainsSum(int[] a, int[] b) {
final Set<Integer> sums = new HashSet<Integer>();
for (int i = 0; i < a.length - 1; i++) sums.add(a[i] + a[i+1]);
for (int x : b) if (sums.contains(x)) return 1;
return 0;
}
The speed does not matter unless you have over 1 million elements and it takes over 1 second. Btw, you do not want to make arrays of size over 1 million elements.
It's not fortunate that Java versions up to 7 do not contain even basic set operations. You can however find them in Google Guava library (that code is properly tested and as efficient as it can be).
Lets say you have 2 sets 20 elements, a and b - that are chosen by random from 1 to 100 and 200.
a = RandomInteger[{100}, 20]
b = RandomInteger[{200}, 20]
After that you want to find what elements of set of a sums of subsequent elements intersects with b
ap = Table[Total[{a[[i]], a[[i + 1]]}], {i, 1, Length[a] - 1}]
Intersection[ap, b]
For example:
{73,43,99,33,80,35,54,82,50,23,92,22,54,4,14,14,8,80,92,85}
{121,139,158,158,51,176,65,84,76,172,73,148,71,128,55,134,4,32,183,134}
{116,142,132,113,115,89,136,132,73,115,114,76,58,18,28,22,88,172,177}
{73,76,172}
When in doubt, use brute force.
Well - of course, if the task is to write a performant solution, that might not be enough, but before you optimize a solution, you need a solution.
val a = List (3, 9, 7, 4, 16)
val b = List (29, 12, 21, 16, 18, 14)
for (i <- (0 to a.length - 2);
j = i+1;
if b.exists (_ == a(i)+a(j))) yield (a(i), a(j), a(i)+a(j))
How often does it run?
The outer loop runs from 1 to array-length-1 (which is a list here) to produce i, j is just the subsequent element.
But for b it runs always through the whole Array,
If you sort b by value, you could do a binary lookup in b.
I guess a HashMap is not allowed from the rules, since you're given two Arrays. Else a HashMap is faster.
I have an array int x[] and a number. I like to do search on the array such that x[i] + x[i+1] = number.
What is the most efficient and fastest way in Java?
Here is a pseudo code, this should work. Only n memory reads.
buff1 = x[0]
buff2 = 0
for i = 1 to n - 1
buff2 = x[i]
if (buff1 + buff2) == number
then
MATCH
endif
buff1 = buff2
endfor
If the array is unsorted and your only doing a few searches use phoxis' method. It's expected to run in O(n*k), where n is the size of x, and k is the number of searches you wan't to make.
If the array is sorted, we know that x[i]<=number/2 and x[i+1]>=number/2. Use binary search to find the (last) predecessor to number/2+1, and check if the match.
int i = binaryPredecessor(x , number/2 + 1);
if(x[i] + x[i+1] == number){
return i;
}
else if(x[i-1] + x[i] == number){
//The case where x[i] == number/2, and we found the last of two occurrences
return i-1;
} else {
//No match exists
return -1;
}
The runtime is O(log(n)*k).
If you do a lot of searches, it might be worth while to sort the array, and use the above method. The array can be sorted in O(n*log(n)) [see mergersort]. So if you want to do more log(n) searches, it's worth to sort the array. (If k is close to log(n), do some testing, to see whats best :) )
Write a static method in Java:
public static void sortByFour (int[] arr)
That receives as a parameter an array full of non-negative numbers (zero or positive) and sorts the array in the following way:
In the beginning of the array all the numbers that are divisible by four will appear.
After them all the numbers in the array that divide by 4 with a remainder of 1 will appear.
After them all the numbers in the array that divide by 4 with a remainder of 2 will appear.
In the end of the array all the rest numbers (those which divide by 4 with the remainder 3) will appear.
(The order of the numbers in each group doesn't matter.)
The method must be as efficient as possible.
The following is what I wrote, but unfortunately it doesn't work well... :(
public static void swap( int[] arr, int left, int right )
{
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
public static void sortByFour( int[] arr )
{
int left = 0;
int right = ( arr.length - 1 );
int mid = ( arr.length / 2 );
while ( left < right )
{
if ( ( arr[left] % 4 ) > ( arr[right] % 4 ) )
{
swap( arr, left, right );
right--;
}
if ( ( arr[left] % 4 ) == ( arr[right] % 4 ) )
left++;
else
left++;
}
}
How do I fix or rewrite my code so that it will work well?
I will do this in psuedocode for you but doing it in code would be giving you the answer and this is homework so you can do your own work. =P
Here is how to do it without lists. This example is restricted based on the requirements but will work once you code it.
int bucketSize = (arr.length() / 4) + 1;
int bucket1[bucketSize];
int bucket2[bucketSize];
int bucket3[bucketSize];
int bucket4[bucketSize];
for (int i=0; i<arr.length; i++) {
if ((arr[i] % 4) == 0)
put arr[i] in bucket 1
else if ((arr[i] % 4) == 1)
put arr[i] in bucket 2
else if ((arr[i] % 4) == 2)
put arr[i] in bucket 3
else
put arr[i] in bucket 4
}
for (int i=0; i<4; i++) {
this will go for each bucket
for (int j=0; j<bucketSize; j++) {
do sort of your choice here to sort the given bucket
the sort you used in your code will do fine (the swapping)
}
}
then concatenate the four buckets in their respective order to get your end result
You can attack the problem like this:
Select a sorting algorithm that you wish to use. It looks like you are trying to program Quicksort, but you could also use Bubble Sort.
Identify the point(s) of the algorithm where two values from the input array are being compared. For example, in the pseudocode for Bubble Sort on the Wikipedia article, the only comparison is the line if A[i] > A[i+1] then....
Figure out a way to compare two numbers so that a number s having remainder 0 when divided by 4 is considered less than a number t having remainder 1 when divided by 4. Replace the comparison operations of the algorithm with your comparator calculation (e.g. if myIsGreater(A[i], A[i+1]) then...).
For step 3, you are definitely on the right track by considering the modulus operator.
I will reiterate what Daniel said: you have your choice of sorting algorithm. Use the most efficient one that you've covered in the class so far, if that is the requirement. But when you get to the point in your algorithm where two items are being compared, compare their value mod 4 instead. So something like if A[i] > A[j] becomes if A[i] % 4 > if A[j] % 4. Then you continue doing whatever the algorithm specifies that you do with that array element. Swap it, bubble it up, return it, whatever is called for.
Regarding the code that you posted, I don't think that it lends itself to a quick fix. Which algorithm is it supposed to be using? What is mid there for? I think that once you know which algorithm you intend to use, and figure out which line of code contains the comparison, you will be able to quickly see and code a solution.
In general, with these sorts of things, it can help if you focus on getting a working solution before you worry about efficiency. I used selection sort the first time I had to do a problem like this. I would recommend trying that first, and then using the experience gained to do one with merge sort, which is O(n log n).
A linear-time solution
The most asymptotically efficient way to do this would be to use bucket sort.
You have 4 buckets, one for each of the congruency class of numbers modulo 4.
Scan the numbers in the array once
Put each number in the right bucket
Then construct the output array
Put all numbers from bucket 0 first, then all from bucket 1, then bucket 2, then bucket 3
Thus, this sorts the numbers in O(N), which is optimal. The key here is that by sorting on numbers modulo 4, there are essentially only 4 numbers to sort: 0, 1, 2, 3.
An illustrative solution with List
Here's an implementation of the above algorithm (for general modulo M) using List and for-each for clarity. Ignore the unchecked cast warning, just concentrate on understanding the algorithm.
import java.util.*;
public class BucketModulo {
public static void main(String[] args) {
final int M = 4;
List<Integer> nums = Arrays.asList(13,7,42,1,6,8,1,4,9,12,11,5);
List<Integer>[] buckets = (List<Integer>[]) new List[M];
for (int i = 0; i < M; i++) {
buckets[i] = new ArrayList<Integer>();
}
for (int num : nums) {
buckets[num % M].add(num);
}
nums = new ArrayList<Integer>();
for (List<Integer> bucket : buckets) {
nums.addAll(bucket);
}
System.out.println(nums);
// prints "[8, 4, 12, 13, 1, 1, 9, 5, 42, 6, 7, 11]"
}
}
Once you fully understand the algorithm, translating this to use arrays (if you must) is trivial.
See also
java.util.List<E> API - "An ordered collection"
add(E e) - "Appends the specified element to the end of this list"
addAll(...) - "Appends all of the elements in the specified collection to the end of this list"
Java Language Guide/The for-each Loop (introduced in 1.5.0)
A special note on %
The stipulation that numbers are non-negative is significant, because % is NOT the modulo operator as it's mathematically defined; it's the remainder operator.
System.out.println(-1 % 2); // prints "-1"
References
JLS 15.17.3 Remainder Operator %
Wikipedia/Modulo operation
Read this page. http://en.wikipedia.org/wiki/Sorting_algorithm#Summaries_of_popular_sorting_algorithms
That should help you best in the long run. It's also pretty fun!
Here's a Java-ish way...
Arrays.sort(arr,new Comparator<Integer>(){
public int compare(Integer a,Integer b)
{
return (a % 4) - (b % 4);
}
});