Double pointer algorithm - sum of two numbers II

Posted by Hobgoblin11 on Fri, 11 Feb 2022 10:01:40 +0100

Give you an integer array numbers with subscript starting from 1. The array has been arranged in non decreasing order. Please find two numbers in the array that meet the sum of addition and equal to the target number target. If the two numbers are numbers[index1] and numbers[index2] respectively, then 1 < = index1 < index2 < = numbers length .

Return the subscripts index1 and index2 of these two integers in the form of an integer array [index1, index2] with length 2.

You can assume that each input only corresponds to a unique answer, and you can't reuse the same elements.

The solution you design must use only constant level extra space.

Example 1:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: the sum of 2 and 7 is equal to the target number 9. So index1 = 1, index2 = 2. Return to [1, 2].

Example 2:

Input: numbers = [2,3,4], target = 6
Output: [1,3]
Explanation: the sum of 2 and 4 is equal to the target number 6. So index1 = 1, index2 = 3. Return to [1, 3].

Example 3:

Input: numbers = [-1,0], target = -1
Output: [1,2]
Explanation: the sum of - 1 and 0 is equal to the target number - 1. So index1 = 1, index2 = 2. Return to [1, 2].

Tips:

  • 2 <= numbers.length <= 3 * 10^4
  • -1000 <= numbers[i] <= 1000
  • numbers are in non decreasing order
  • -1000 <= target <= 1000
  • Only one valid answer exists
analysis

For such problems, the most brainless method is double loop traversal:

vector<int> twoSum(vector<int>& numbers, int target) {
	vector<int> retVec;
	for (int i = 0; i < numbers.size() - 1; i++) {
		for (int j = i + 1; j < numbers.size(); j++) {
			if ((numbers[i] + numbers[j]) == target) {
				retVec.push_back(i + 1);
				retVec.push_back(j + 1);
			}
		}
	}
	return retVec;
}

However, it is impossible to pass the following particularly long test cases.

At that time, i thought that i could use the method similar to sliding window to find the qualified solution by using the two pointers i and j to continuously slide to the right as a whole. Although it is much faster than double loop and can pass the test case, it still can not reach O(n) and is extremely unstable. It can reach O(n) when it is fast and close to O(n^2) when it is slow. The code is not concise and beautiful:

//leetcode-167 sliding window
vector<int> twoSum(vector<int>& numbers, int target) {
	if (numbers.size() <= 1)
		return vector<int>();
	vector<int> retVec;
	int i = 0, j = 1;
	while (i < j) {
		cout << "i = " << i << "\tj = " << j << "\t" << numbers[i] << " + " << numbers[j] << " = " << numbers[i] + numbers[j] << endl;
		if (numbers[i] + numbers[j] < target) {//Move j right if insufficient
			//If j has reached the maximum value, i shifts to the right
			if (j < numbers.size() - 1)
				j++;
			else
				i++;
		}
		else if (numbers[i] + numbers[j] == target) {//Equals description found
			retVec.push_back(i + 1);
			retVec.push_back(j + 1);
			break;
		}
		else {//If it is greater than target, it is meaningless for J to move to the right again. At this time, I should be moved to the right by 1 bit, and j should be continuously moved to the left until numbers[i] + numbers[j]
			i++;
			while (j > i) {
				j--;
				if (numbers[i] + numbers[j] <= target)
					break;
			}
		}
	}
	return retVec;
}

Finally, I saw the head and tail pointers used by the great gods approaching the middle, concise and efficient. The best method is often the clearest and simplest method. Although complex and bloated methods can solve problems, they are far from artistic.

vector<int> twoSum(vector<int>& numbers, int target) {
    vector<int> retVec;
    int i = 0, j = numbers.size() - 1;
    while (i < j) {
        int sum = numbers[i] + numbers[j];
        if(sum == target){
            retVec.push_back(i + 1);
            retVec.push_back(j + 1);
            break;
        }else if(sum < target) i++;
        else j--;
    }
    return retVec;
}

Topics: C++ Algorithm leetcode Dynamic Programming Double Pointer