查找和为指定数的数组数字

51 阅读4分钟

题目解析

这道题目要求在一个按升序排列的整数数组中,寻找两数之和等于目标值的第一对数字。如果找到符合条件的两数,返回一个包含状态标志和这两个数的结果;如果未找到,返回一个包含状态标志的异常结果。


问题分解

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}));
}

}`

总结

  1. 双指针法:

    • 利用数组的升序特点,双指针可以在 O(n)O(n) 的时间内高效找到符合条件的两数。
    • 与暴力法的 O(n2)O(n2) 相比,显著提高了性能。
  2. 多样化的测试样例:

    • 样例覆盖了有解和无解的情况。
    • 样例验证了算法能正确处理负数和非负数组合。
  3. 边界条件处理:

    • 空数组或单元素数组无需额外处理,因为指针范围自动限制了操作。

最终,该算法以较高的效率和易于理解的逻辑,解决了寻找两数之和的问题。