This is the 13th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Topic describes

Given an array of integers in non-decreasing order numbers, find two numbers that add up to the target number. The function should have length2Returns the subscript values of both numbers in the form of an array of integers. Numbers subscript from1Start counting, so the answer array should satisfy1 <= answer[0] < answer[1) < = Numbers. Length. You can assume that each input corresponds to a unique answer, and you can't reuse the same elements. The sample1: input: numbers = [2.7.11.15], target = 9Output:1.2] :27The sum is equal to the number of targets9. So the index1 =1, index2 = 2. The sample2: input: numbers = [2.3.4], target = 6Output:1.3] example3: Enter: numbers = [-1.0], target = -1Output:1.2] :2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000Numbers are in non-decreasing order -1000 <= target <= 1000Only one valid answer exists source: LeetCode//leetcode-cn.com/problems/two-sum-ii-input-array-is-sortedCopyright belongs to the Collar buckle network. Commercial reprint please contact official authorization, non-commercial reprint please indicate the source.Copy the code

Ideas & CODE

1. The hash

It seems that this kind of finding element of the problem can be hashed, but generally not optimal solution, comparison needs to open up extra space

Get (target- current element) is used to retrieve the current element index as long as map.get(target- current element) is not null. And, of course, they say I is less than j, so we have to evaluate the size of the element and return it

public int[] twoSum1(int[] numbers, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < numbers.length; i++) {
        map.put(numbers[i], i);
    }
    for (int i = 0; i < numbers.length; i++) {
        Integer index = map.get(target - numbers[i]);
        if(index ! =null) {
            if (i > index) {
                return new int[]{index+1, i+1};
            } else {
                return new int[]{i+1, index+1}; }}}return new int[] {-1, -1};
}
Copy the code

Time complexity O(n), space complexity O(n)

Binary search

And since they’re conditional, they’re increasing the array. So we iterate over an element, use target- this element to get another element, and then bisect after that element to find another element.

public int[] twoSum2(int[] numbers, int target) {
    for (int i = 0; i < numbers.length; i++) {
        int left = i + 1;
        int right = numbers.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (numbers[i] + numbers[mid] == target) {
                return new int[]{i + 1, mid + 1}; 
            } else if (numbers[i] + numbers[mid] < target) {
                left = mid + 1;
            } else if (numbers[i] + numbers[mid] > target) {
                right = mid - 1; }}}return new int[] {-1, -1};
}
Copy the code

Traversal takes n time, binary takes logn, so time is order logn.

3. Double pointer

When writing this topic, I looked at the tag. Although I saw the double pointer, I still couldn’t think of the solution after thinking for a long time.

Each time the loop computes the sum of the first pointer elements, and moves the left pointer to the right if it is less than target. Greater than target moves the right pointer to the left. The condition of the while is left < right. Returns the index position if the sum of the leading and trailing Pointers equals target

The problem with this solution is, will I miss elements if I move the pointer this way?

Read the solution found a wonderful idea!

Will not repeat the record, you can see the link below; In short, all of the combinations in this problem can fit into a rectangle, and this rectangle has n^2 little rectangles, and each little rectangle is a combination of elements. Violent loops exclude one small rectangle at a time, while double Pointers exclude one row (column) of rectangles at a time!

Use double Pointers to reduce the search space

public int[] twoSum3(int[] numbers, int target) {
    int left = 0;
    int right = numbers.length - 1;
    while (left < right) {
        if (numbers[left] + numbers[right] == target) {
            return new int[]{left + 1, right + 1};
        } else if (numbers[left] + numbers[right] > target) {
            right--;
        } else if(numbers[left] + numbers[right] < target) { left++; }}return new int[] {-1, -1};
}
Copy the code