剑指offer57:和为s的数字
题目描述:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
输入数组{1,2,4,7,11,15}和数字15,数组中4+11=15,因此输入4和11。
首先分析这个数组是递增排序的,那么数组越往后,数组的值会越大,假设取数组中两个值A和B,A+B=19>s,那么想让和更小,只能往数组前面取比B还小的数字了;如果A+B=11<s,那么为了让和更大,就需要往数组后面取比A大的数字了。先处理数组头部和尾部的元素,看是否满足要求,不满足,根据比较策略,往中间找值,如果找到,就返回这一组数。go代码实现:
1 func twoSum(nums []int, target int) []int { 2 if len(nums) == 0 { 3 return nil 4 } 5 6 var num[]int 7 i := 0 8 j := len(nums) - 1 9 for i < j { 10 if nums[i] + nums[j] == target { 11 num = append(num, nums[i]) 12 num = append(num, nums[j]) 13 break 14 } else if nums[i] + nums[j] < target { 15 i++ 16 } else if nums[i] + nums[j] > target { 17 j-- 18 } 19 } 20 21 return num 22 }
把上述题目稍作变换,得到另一个相似问题。
题目描述:输入一个正数,打印出所有和为s的连续正数序列(至少含有两个数)。例如,输入15,由于1+2+3+4+5=4+5+6=7+8==15,所以打印出3个连续序列1~5、4~6和7~8。
分析:根据上一个题目的思路,还是选择根据当前序列和与目标值的大小关系,来从序列中删除、添加元素。首先从数字1、2开始处理,不断增大值,直到序列的和满足要求,题目要求所有的和为目标值的序列,找到一个后继续找。只能不断增大右区间值,缩小左区间值来往后找,因为题目要求至少含有两个数,所以,当左区间到(1+s)/2的时候,就不能再往后找了,再往后找两个值加起来肯定大于s了,所以,左区间的最大范围就是(1+s)/2了,基于分析思路,go实现代码:
1 func findContinuousSequence(target int) [][]int { 2 //序列要求至少包含两个数,1+2=3了,假设目标值<3,那就没有找的必要了 3 if target < 3 { 4 return nil 5 } 6 7 low := 1 8 high := 2 9 sum := low + high 10 middle := (1 + target)/2 11 var result[][]int 12 for low < middle { 13 //找到了一个满足要求的序列,打印出来 14 if sum == target { 15 //printfNum(low, high, result) 16 result = append(result, printfNum(low, high)...) 17 } 18 19 //看看还有没有别的序列满足要求 20 for low < middle && sum > target { 21 sum = sum - low 22 low ++ 23 if sum == target { 24 //printfNum(low, high, result) 25 result = append(result, printfNum(low, high)...) 26 } 27 } 28 29 //要输出所有满足要求的序列,那就继续增大high的值,继续找 30 high++ 31 sum = sum + high //更新sun值 32 } 33 34 return result 35 } 36 37 func printfNum(val1 int, val2 int) (result [][]int) { 38 var num []int 39 for val1 <= val2 { 40 num = append(num, val1) 41 val1++ 42 } 43 result = append(result, num) 44 return result 45 }