题目解析
这道题目要求在一个按升序排列的整数数组中,寻找两数之和等于目标值的第一对数字。如果找到符合条件的两数,返回一个包含状态标志和这两个数的结果;如果未找到,返回一个包含状态标志的异常结果。
问题分解
1. 输入与输出
- 输入:
arr: 一个升序排序的整数数组。target: 一个目标和的整数。
- 输出:
- 如果找到符合条件的两数,返回一个数组
[1, 数字1, 数字2],其中:1表示成功找到。数字1和数字2是符合条件的两个整数。
- 如果找不到,返回一个数组
[0, 0, 0],其中:0表示未找到。
- 如果找到符合条件的两数,返回一个数组
2. 题目特点
- 升序数组:
- 数组按升序排序意味着可以使用双指针法来高效解决问题。
- 唯一解或第一解:
- 需要返回找到的第一对符合条件的数字,这要求从左到右按顺序查找。
- 不存在解的处理:
- 如果数组中不存在符合条件的组合,则返回异常标志。
解题思路
为了高效查找两数之和等于目标值的组合,可以采用双指针法。具体步骤如下:
1. 初始化双指针
- 使用两个指针
left和right:left初始化为数组的起始位置,指向较小的数。right初始化为数组的末尾位置,指向较大的数。
2. 计算两数和
- 计算
arr[left] + arr[right]:- 如果两数和等于目标值
target,返回结果[1, arr[left], arr[right]]。 - 如果两数和小于目标值,说明需要增大和的值,移动左指针
left++。 - 如果两数和大于目标值,说明需要减小和的值,移动右指针
right--。
- 如果两数和等于目标值
3. 边界条件
- 当
left >= right时,说明数组中不存在满足条件的组合,返回异常结果[0, 0, 0]。
4. 时间复杂度
- 时间复杂度:
- 每次移动一个指针,最多遍历整个数组一次,因此复杂度为 O(n)O(n)。
- 空间复杂度:
- 仅使用了常量级别的辅助空间,复杂度为 O(1)O(1)。
测试样例分析
样例1
- 输入:
arr = [1, 2, 4, 7, 11, 15],target = 6 - 分析:
- 初始
left = 0, right = 5:arr[left] + arr[right] = 1 + 15 = 16,大于目标值,移动right--。
left = 0, right = 4:arr[left] + arr[right] = 1 + 11 = 12,大于目标值,移动right--。
left = 0, right = 3:arr[left] + arr[right] = 1 + 7 = 8,大于目标值,移动right--。
left = 0, right = 2:arr[left] + arr[right] = 1 + 4 = 6,等于目标值,返回[1, 2, 4]。
- 初始
- 输出:
[1, 2, 4]
样例2
- 输入:
arr = [1, 3, 5, 8, 12],target = 10 - 分析:
- 初始
left = 0, right = 4:arr[left] + arr[right] = 1 + 12 = 13,大于目标值,移动right--。
left = 0, right = 3:arr[left] + arr[right] = 1 + 8 = 9,小于目标值,移动left++。
left = 1, right = 3:arr[left] + arr[right] = 3 + 8 = 11,大于目标值,移动right--。
left = 1, right = 2:arr[left] + arr[right] = 3 + 5 = 8,小于目标值,移动left++。
left = 2, right = 2,指针相遇,无解,返回[0, 0, 0]。
- 初始
- 输出:
[0, 0, 0]
样例3
- 输入:
arr = [-10, -3, 0, 4, 5],target = 1 - 分析:
- 初始
left = 0, right = 4:arr[left] + arr[right] = -10 + 5 = -5,小于目标值,移动left++。
left = 1, right = 4:arr[left] + arr[right] = -3 + 5 = 2,大于目标值,移动right--。
left = 1, right = 3:arr[left] + arr[right] = -3 + 4 = 1,等于目标值,返回[1, -3, 4]。
- 初始
- 输出:
[1, -3, 4]
`import java.util.Arrays;
public class Main { public static int[] solution(int[] arr, int target) { int left = 0; int right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) {
return new int[]{1, arr[left], arr[right]};
} else if (sum < target) {
left++;
} else {
right--;
}
}
// 如果没有找到符合条件的组合,返回异常标志
return new int[]{0, 0, 0};
}
public static void main(String[] args) {
System.out.println(Arrays.equals(solution(new int[]{1, 2, 4, 7, 11, 15}, 6), new int[]{1, 2, 4}));
System.out.println(Arrays.equals(solution(new int[]{1, 3, 5, 8, 12}, 10), new int[]{0, 0, 0}));
System.out.println(Arrays.equals(solution(new int[]{-10, -3, 0, 4, 5}, 1), new int[]{1, -3, 4}));
}
}`
总结
-
双指针法:
- 利用数组的升序特点,双指针可以在 O(n)O(n) 的时间内高效找到符合条件的两数。
- 与暴力法的 O(n2)O(n2) 相比,显著提高了性能。
-
多样化的测试样例:
- 样例覆盖了有解和无解的情况。
- 样例验证了算法能正确处理负数和非负数组合。
-
边界条件处理:
- 空数组或单元素数组无需额外处理,因为指针范围自动限制了操作。
最终,该算法以较高的效率和易于理解的逻辑,解决了寻找两数之和的问题。