O (n log (n)), which checks if the sum of two numbers in int [] = a given number

I have to create an O(n log(n)) algorithm that checks if the sum of two numbers in int [] == is the given number.

eg. Given [1,4,7,2,3,4], there will be a sum of 8 (1 + 7), but not 20

This answer suggested a binary sort or merge sort, but they just gave a merge sort algorithm without the logical processing of this particular requirement. Then there was another answer:

Suppose x is the sum we want to check, z is the set of elements from this array: The following algorithm solves the problem:

  • Sort items in S.
  • Make up the set S = {z: z = x - y for some y ∈ S}.
  • Sort items in S.
  • If any value in S appears more than once, delete all but one instance. Do the same for S.
  • Combine the two sorted sets S and S.
  • There are two elements in S whose sum is exactly equal to x if and only if the same value appears in consecutive positions in the combined output.

To substantiate the claim in step 4, we first note that if any value appears twice in the combined output, it must appear in a sequential position. Thus, we can reformulate the condition in step 5, since there are two elements in S whose sum is exactly equal to x if and only if the same value appears twice in the combined output. Suppose some value of w appears twice. Then w appears once in S and once in S. Since w appeared in S, there exists some y ∈ S such that w = x - y or x = w + y. Since w ∈ S, the elements w and y are in S and summed with x.

Conversely, suppose that there exist values ​​w, y ∈ S such that w + y = X. Then, since x - y = w, the value of w appears in S. Thus, w is in both S and S, and therefore it will be displayed twice in the combined output.

Steps 1 and 3 require steps O (n log n). Steps 2, 4, 5, and 6 require O (n). Thus, the total runtime is O (n log n).

But I do not understand what they had in mind. In step 2, what are x and y?

But I created in my own way, interestingly, its O(n log(n)) ?

 class FindSum { public static void main(String[] args) { int[] arr = {6,1,2,3,7,12,10,10}; int targetSum = 20; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); int end = arr.length - 1; if (FindSum.binarySearchSum(arr, targetSum, 0, end, 0, end)) { System.out.println("Found!"); } else { System.out.println("Not Found :("); } } public static boolean binarySearchSum(int[] arr, int targetSum, int from1, int end1, int from2, int end2) { // idea is to use 2 "pointers" (simulating 2 arrays) to (binary) search // for target sum int curr1 = from1 + (end1-from1)/2; int curr2 = from2 + (end2-from2)/2; System.out.print(String.format("Looking between %d to %d, %d to %d: %d, %d", from1, end1, from2, end2, curr1, curr2)); int currSum = arr[curr1] + arr[curr2]; System.out.println(". Sum = " + currSum); if (currSum == targetSum) { // base case return true; } else if (currSum > targetSum) { // currSum more than targetSum if (from2 != end2) { // search in lower half of 2nd "array" return FindSum.binarySearchSum(arr, targetSum, from1, end1, from2, curr2 - 1); } else if (from1 != end2) { // search in lower half of 1st "array" (resetting the start2, end2 args) return FindSum.binarySearchSum(arr, targetSum, from1, curr1 - 1, 0, arr.length - 1); } else { // can't find return false; } } else { // currSum < targetSum if (from2 != end2) { // search in upper half of 2nd "array" return FindSum.binarySearchSum(arr, targetSum, from1, end1, curr2 + 1, end2); } else if (from1 != end2) { // search in upper half of 1st "array" (resetting the start2, end2 args) return FindSum.binarySearchSum(arr, targetSum, curr1 + 1, end1, 0, arr.length - 1); } else { // can't find return false; } } } } 
+3
source share
5 answers

Similar to @ user384706, you can do this with O(n) .

They say the following: S = [1,4,7,2,3,4]

Add them to the 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 
+5
source

They say the following:
S=[1,4,7,2,3,4]

Sorting S using mergesort you get Ss=[1,2,3,4,7] . Cost O(nlogn) - just check the wiki.

Then you have x=8
So you form S'=[7,6,5,4,1] by subtracting x with elements in S
Sort S' with mergesort in O(nlogn)
Duplicate removal requires O(n) .

Then you combine Ss and S' .
You check for duplicates in consecutive positions in O(n) .
Total: O(nlogn)+O(nlogn)+O(n)+O(n)+O(n) = O(nlogn)

+4
source

How about a solution to O (n)?

It is not clear from your question whether you are using what you called the “other answer” [sic], or if you can come up with your own solution.

The first thing you should ask: "What are the requirements?" Because there are limitations. What is the maximum number of integers you get? Two million? Ten millions? What is the range of these integers? In your question, they always seem to be greater than zero. What maximum value can these integers have? How much memory can you use?

Because there are always compromises.

For example, the O (n) solution for your problem is not optimized (see below) (I added "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 is not optimized in that it easily writes O (n), working for integers from 0 to 2 ** 31, using “only” 1 GB of memory (where instead of S and S you should use bits instead of such as, for example , here).

Of course, you might think: “but 1 GB is a big memory”: but it all depends on the requirements. My solution above (or its optimized version) is O (n) and can instantly allow input consisting, for example, of 100 million integers when some other solution fails (since you would have OutOfMemory errors due to overhead of Java objects).

The first thing to ask is "What are the requirements?" You need more input information, because it is always a compromise.

+3
source

Your algorithm is O (n log n). Each time you either split the 1st size of the array into two, or perform a binary search on the second. This is O ((log n) ^ 2) the worst case (i.e., S = {1,2 ..., n} and x = 0) and therefore it is absorbed by sorting.

In any case, you can make it a little easier in O (n log n):

  • array sorting (O (n log n))
  • iteration of its elements (O (n)), while in each iterative binary search (O (log n)) for the X-complement of the current element.

edit: In response to your first question. x is the sum you are looking for, and y are elements of the input dataset. 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}

0
source

It works as follows:

  • Sort input array
  • create two variables front = 0 [start point] rear = array length [end point].
  • It starts at both ends of the array, calculates its sum if it is zero, both front and back
  • unless you enlarge the side containing the larger element. [since the array is sorted, there is no way to find the element so that their sum is 0]
  • stop when front> = rear.

 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)); } 

}

0
source

Source: https://habr.com/ru/post/1438339/


All Articles