代码训练(37)两数之和
Author: Once Day Date: 2025年6月22日
漫漫长路,才刚刚开始…
全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客
参考文章:
1. 原题
给你一个下标从 1 开始的整数数组
numbers
,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数target
的两个数。如果设这两个数分别是numbers[index1]
和numbers[index2]
,则1 <= index1 < index2 <= numbers.length
。以长度为 2 的整数数组
[index1, index2]
的形式返回这两个整数的下标index1
和index2
。你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers
按 非递减顺序 排列-1000 <= target <= 1000
- 仅存在一个有效答案
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
2. 分析
给定一个已经按非递减顺序排列的整数数组 numbers
,我们需要找到两个数,它们的和正好等于给定的目标数 target
。返回这两个数的下标(从1开始计数),确保第一个下标小于第二个下标。题目保证有唯一解,并且不允许重复使用相同的元素。
由于数组已经是排序过的,我们可以利用双指针技术来解决这个问题。具体步骤如下:
-
初始化两个指针:
left
指向数组的开始(下标 1),right
指向数组的结束(下标numbers.length
)。 -
遍历数组
:通过循环移动两个指针来寻找两个数:
- 如果
numbers[left] + numbers[right]
等于target
,则找到了正确的组合。 - 如果和小于
target
,由于数组是非递减的,为了增加和的值,向右移动left
指针。 - 如果和大于
target
,为了减少和的值,向左移动right
指针。
- 如果
-
返回结果:当找到符合条件的两个数时,返回它们的下标。
例如,对于输入 numbers = [2, 3, 4]
和 target = 6
:
- 初始化
left = 1
和right = 3
。 - 计算和
2 + 4 = 6
,这恰好等于目标值6
。 - 返回
[1, 3]
。
性能优化关键点:
- 空间复杂度:由于使用的是双指针技术,除了返回结果外,没有使用额外的数据结构,因此空间复杂度为 O(1)。
- 时间复杂度:双指针遍历一次数组,时间复杂度为 O(n)。
3. 代码实现
#include <stdio.h>
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {
int left = 0;
int right = numbersSize - 1;
*returnSize = 2;
int* result = (int*)malloc(2 * sizeof(int)); // 动态分配返回数组
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum == target) {
result[0] = left + 1; // 返回的下标从1开始
result[1] = right + 1;
return result;
} else if (sum < target) {
left++;
} else {
right--;
}
}
return result; // 此处返回是为了避免编译警告,实际上题目保证有解
}
int main() {
int numbers[] = {2, 3, 4};
int target = 6;
int returnSize;
int* indices = twoSum(numbers, sizeof(numbers) / sizeof(numbers[0]), target, &returnSize);
printf("[%d, %d]\n", indices[0], indices[1]);
free(indices); // 释放动态分配的内存
return 0;
}
4. 总结
这个题目考察了对排序数组的双指针技巧的应用,对于非递减数组中的两数之和问题,双指针方法非常高效。通过这类问题的练习,可以加深对数组操作和双指针技巧的理解和掌握。为了进一步提升编程能力,建议练习更多使用双指针解决的问题,如三数之和、最接近的三数之和等。