
算法题
聊回技术。
今天这道题,是我在刷LeetCode时看到的。题目叫"两数之和 II",给定一个已按升序排列的数组,找出两个数使它们相加之和等于目标数。
为啥选这道题?
因为看到大家讨论"点奶茶选口味",我突然想到——这不就是一个选择匹配的问题吗?
AI问你"要几分糖、几分冰",本质上也是在数组里找到合适的组合。
给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
注意:返回的下标值不是从零开始的,而是从1开始。
示例:
输入: numbers = [2,7,11,15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9。因此 index1 = 1, index2 = 2。
暴力解法:两层循环遍历所有可能的组合,时间复杂度O(n²)。
但数组是有序的,这个条件很关键,我们可以利用它来优化。
双指针解法:
这样只需要遍历一遍,时间复杂度O(n)。
package main
import (
"fmt"
)
// twoSum 双指针解法
func twoSum(numbers []int, target int) []int {
left, right := 0, len(numbers)-1
for left < right {
sum := numbers[left] + numbers[right]
if sum == target {
// 题目要求下标从1开始
return []int{left + 1, right + 1}
} else if sum < target {
// 和太小,左指针右移,需要更大的数
left++
} else {
// 和太大,右指针左移,需要更小的数
right--
}
}
// 根据题意,一定存在解
return []int{-1, -1}
}
func main() {
// 测试用例1
numbers1 := []int{2, 7, 11, 15}
target1 := 9
fmt.Printf("输入: numbers = %v, target = %d\n", numbers1, target1)
fmt.Printf("输出: %v\n\n", twoSum(numbers1, target1))
// 预期输出: [1, 2]
// 测试用例2
numbers2 := []int{2, 3, 4}
target2 := 6
fmt.Printf("输入: numbers = %v, target = %d\n", numbers2, target2)
fmt.Printf("输出: %v\n\n", twoSum(numbers2, target2))
// 预期输出: [1, 3]
// 测试用例3:包含负数
numbers3 := []int{-1, 0}
target3 := -1
fmt.Printf("输入: numbers = %v, target = %d\n", numbers3, target3)
fmt.Printf("输出: %v\n", twoSum(numbers3, target3))
// 预期输出: [1, 2]
}
left < right 而不是 left <= right