I am supposed to create a O(n log(n))
algorithm that checks if sum of 2 numbers in a int[] == given number.
eg. Given [1,4,7,2,3,4] there will be a sum
Your algorithm is O(n log n). Each time you either divide 1st array size by two or do a binary search on the second one. This is O((log n) ^2) worst case (ie. S = {1,2...,n} and x = 0) and hence it's absorbed by sorting.
Anyway you can do it a bit easier in O(n log n) by:
edit: In response to your first question. x is the sum you're looking for and y are the elements of the input set. So if S= {y_1, y_2, y_3,..., y_n} then S' = {x - y_1, x - y_2, x - y_3, ...x - y_n}
It works as following :
public class TwoSumFaster {
private static int countTwoSum(int[] numbers) {
int count = 0;
int front = 0, rear = numbers.length - 1;
while (front < rear) {
if (numbers[front] + numbers[rear] == 0) {
front++;
rear--;
count++;
} else {
if (Math.abs(numbers[front]) > Math.abs(numbers[rear])) {
front++;
} else {
rear--;
}
}
}
return count;
}
public static void main(String[] args) {
int[] numbers = { 1, 3, 5, 7, 12, 16, 19, 15, 11, 8, -1, -3, -7, -8, -11, -17, -15 };
Arrays.sort(numbers);
System.out.println(countTwoSum(numbers));
}
}
What about an O(n) solution?
It's not clear from your question if you're supposed to use what you described as "another answer" [sic] or if you can come up with your own solution.
The first thing you should ask is "what are the requirements?" Because there are limitations. What's the maximum number of integers you'll receive? Two millions? Ten millions? What's the range of these integers? In your question they always seem greater than zero. What's the maximum value these integers can have? How much memory can you use?
Because there are always tradeoffs.
For example here's a non-optimized (see below) O(n) solution to your problem (I added an '8' to your input):
@Test
public void testIt() {
final int max = 10000000;
final int[] S = new int[max+1];
final int[] in = { 1, 4, 3, 2, 4, 7, 8 };
for ( final int i : in ) {
S[i]++;
}
assertFalse( containsSum(S, 1) );
assertFalse( containsSum(S, 2) );
assertTrue( containsSum(S, 3) );
assertTrue( containsSum(S, 4) );
assertTrue( containsSum(S, 5) );
assertTrue( containsSum(S, 6) );
assertTrue( containsSum(S, 7) );
assertTrue( containsSum(S, 8) );
assertTrue( containsSum(S, 9) );
assertTrue( containsSum(S, 10) );
assertTrue( containsSum(S, 11) );
assertFalse( containsSum(S, 13) );
assertFalse( containsSum(S, 14) );
assertTrue( containsSum(S, 12) );
assertTrue( containsSum(S, 15) );
assertFalse( containsSum(S, 16) );
}
private static boolean containsSum( final int[] ar, final int sum ) {
boolean found = false;
for (int i = 1; i < sum && !found; i++) {
final int b = sum - i;
found = i == b ? ar[i] > 1 : ar[i] > 0 && ar[b] > 0;
}
return found;
}
It's non optimized in that it's easy to write an O(n) working for integers from 0 to 2**31 using "only" 1 GB of memory (where you'd represent your S and your S' using bits instead of ints like I did here).
Sure, one may think "but 1GB is a lot of memory": but it all depends on the requirements. My solution above (or an optimized version of it) is O(n) and can solve an input made of, say, 100 millions integers in no time, where any other solution would fail (because you'd have OutOfMemory errors due to the overhead of Java objects).
The first thing to ask is "What are the requirements?". You need more information about the input because it's always a tradeoff.
Similar to @user384706, however you can do this with in O(n)
.
What they say is the following: S=[1,4,7,2,3,4]
Add these to a HashSet, ideally TIntHashSet (but the time complexity is the same)
int total = 9;
Integer[] S = {1, 4, 7, 2, 3, 4, 6};
Set<Integer> set = new HashSet<Integer>(Arrays.asList(S));
for (int i : set)
if (set.contains(total - i))
System.out.println(i + " + " + (total - i) + " = " + total);
prints
2 + 7 = 9
3 + 6 = 9
6 + 3 = 9
7 + 2 = 9
What they say is the following:
S=[1,4,7,2,3,4]
Sort S using mergesort you get Ss=[1,2,3,4,7]
. Cost is O(nlogn)
- just check wiki for this.
Then you have x=8
So you form S'=[7,6,5,4,1]
by subtracting x
with the elements in S
.
Sort S'
using mergesort in O(nlogn)
Remove duplicates requires O(n)
.
Then you merge the Ss
and S'
.
You check for duplicates in consecutive positions in O(n)
.
Total is:
O(nlogn)+O(nlogn)+O(n)+O(n)+O(n) = O(nlogn)