In java
private static boolean find(int[] nums, long k, int[] ids) { // walk from both sides towards center. // index[0] keep left side index, index[1] keep right side index, // runtime O(N) int l = ids[0]; int r = ids[1]; if (l == r) { ids[0] = -1; ids[1] = -1; return false; } if (nums[l] + nums[r] == k) { ids[0]++; ids[1]++; return true; } if (nums[l] + nums[r] < k) { ids[0]++; } else { ids[1]--; } return find(nums, k, ids); } public static boolean twoSum(final int[] nums, int target) { // Arrays.sort(nums); //if the nums is not sorted, then sorted it firstly, thus the running time will be O(NlogN) int[] ids = new int[2]; ids[0] = 0; ids[1] = nums.length - 1; return find(nums, target, ids); }
Test
@Test(timeout = 10L, expected = Test.None.class) public void test() { Assert.assertEquals( twoSum(new int[]{3, 2, 4}, 6), true); Assert.assertEquals( twoSum(new int[]{3, 2, 4}, 8), false); }
IF only the answer is not enough and you want to know which one I and j are, that A [i] + A [j] = target
with @cheeken's idea as follows: if there is a duplicate number, take the first that appears first.
public static int[] twoSum2(final int[] nums, int target) { int[] r = new int[2]; r[0] = -1; r[1] = -1; Set<Integer> set = new HashSet<>(nums.length); Map<Integer, List<Integer>> map = new HashMap<>(nums.length); for (int i = 0; i < nums.length; i++) { int v = nums[i]; if (set.contains(target - v)) { r[0] = map.get(target - v).get(0); r[1] = i; return r; } set.add(v); List ids = map.get(v); if (ids == null) { ids = new LinkedList<>(); ids.add(i); map.put(v, ids); } else { ids.add(i); map.put(v, ids); } } return r; }
Test
int[] r = twoSum2(new int[]{3, 2, 4}, 6); Assert.assertEquals(r[0], 1); Assert.assertEquals(r[1], 2); r = twoSum2(new int[]{3, 2, 4}, 8); Assert.assertEquals(r[0], r[1]); Assert.assertEquals(r[1], -1);