1879. Two Sum VII
Given an array of integers that is already sorted in ascending absolute order, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are zero-based.
You are not allowed to sort this array.
Example
Input:
[0,-1,2,-3,4]
1
Output: [[1,2],[3,4]]
Explanation: nums[1] + nums[2] = -1 + 2 = 1, nums[3] + nums[4] = -3 + 4 = 1
You can return [[3,4],[1,2]], the system will automatically help you sort it to [[1,2],[3,4]]. But [[2,1],[3,4]] is invaild.
Challenge
O(n) time complexity and O(1) extra space
Notice
- It is guaranteed that all numbers in the nums is distinct.
- The length of nums≤100000.
- The number in nums is 10^9.
Input test data (one parameter per line)How to understand a testcase?
解法1:
我的解法是先找出所有数里面的最小值和最大值。然后就可以跟经典的two sum一样处理了。
一开始,start = 所有数里面的最小值,end = 所有数里面的最大值。
如果nums[start] + nums[end] < target,移动start
如果nums[start] + nums[end] > target,移动end
如果nums[start] + nums[end] == target,把{start, end}放入res中,同时移动start和end
注意:
- 移动start时,如果nums[start] < 0,我们要移动到下一个大一点的负数,那么start应该–,往左移动。
但当nums[start]已经是最大的那个负数了,我们要把start移动到最小的那个正数或0(minPosIndex)。如果nums[start]>0,那么就跟经典的two sum一样,start++,往右移动。 - 移动end跟上面类似。
- 所以我们要首先保存4个变量,minNegIndex, maxNegIndex, minPosIndex, maxPosIndex。
- while 循环的条件不是(start < end),因为这里start和end位置不定,有可能start在end右边。我选择的while循环条件如下。
while ((start != origEnd || end != origStart) && start >= 0 && start < n && end >= 0 && end < n)
- 为了避免重复,我们只将 start < end 的{start, end}输入res。
- 最后还要考虑if (start == origEnd && end == origStart) 的情况
class Solution {
public:
/**
* @param nums: the input array
* @param target: the target number
* @return: return the target pair
*/
vector<vector<int>> twoSumVII(vector<int> &nums, int target) {
int n = nums.size();
vector<vector<int>> res;
for (int i = 0; i < n; ++i) {
if (nums[i] >= 0 && minPosIndex < 0) {
minPosIndex = i;
}
if (nums[i] < 0 && maxNegIndex < 0) {
maxNegIndex = i;
}
if (minPosIndex >= 0 && maxNegIndex >= 0) break;
}
for (int i = n - 1; i >= 0; --i) {
if (nums[i] >= 0 && maxPosIndex < 0) {
maxPosIndex = i;
}
if (nums[i] < 0 && minNegIndex < 0) {
minNegIndex = i;
}
if (maxPosIndex >= 0 && minNegIndex >= 0) break;
}
start = minNegIndex >= 0 ? minNegIndex : minPosIndex;
end = maxPosIndex >= 0? maxPosIndex : maxNegIndex;
int origStart = start, origEnd = end;
while ((start != origEnd || end != origStart) && start >= 0 && start < n && end >= 0 && end < n) {
int sum = nums[start] + nums[end];
if (sum < target) {
moveStart(nums);
} else if (sum > target) {
moveEnd(nums);
} else {
if (start < end) res.push_back({start, end});
moveStart(nums);
moveEnd(nums);
}
}
if (start == origEnd && end == origStart && nums[start] + nums[end] == target && start < end) res.push_back({start, end});
return res;
}
private:
int start, end;
int minNegIndex = -1, maxNegIndex = -1, minPosIndex = -1, maxPosIndex = -1;
void moveStart(vector<int> &nums) {
int n = nums.size();
if (nums[start] < 0 && nums[start] < nums[maxNegIndex]) {
do {
start--;
if (nums[start] < 0) break;
} while (start >= 0);
} else if (nums[start] < 0 && nums[start] == nums[maxNegIndex]) {
start = minPosIndex;
} else {//if (minPosIndex >= 0) { //may not need if (minPosIndex >= 0)
do {
start++;
if (nums[start] >= 0) break;
} while (start < n);
}
}
void moveEnd(vector<int> &nums) {
int n = nums.size();
if (nums[end] >= 0 && nums[end] > nums[minPosIndex]) {
do {
end--;
if (nums[end] >= 0) break;
} while (end >= 0);
} else if (nums[end] >= 0 && nums[end] == nums[minPosIndex]) {
end = maxNegIndex;
} else {// if (maxNegIndex >= 0){ //may not need if (maxNegIndex >= 0)
do {
end++;
if (nums[end] < 0) break;
} while (end < n);
}
}
};