问题一:和为s的两个数
问题描述:
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]
示例 2:
输入:nums = [10,26,30,31,47,60], target = 40
输出:[10,30] 或者 [30,10]
解题思路:
由于数组是递增的,所以可以使用双指针的解法,刚开始两个指针分别指向数组的头和尾,当和小于target时左指针向有移动,取一个更大的值;当和大于target时右指针向做移动,取一个更小的值。
这题不要想得太多而用尺取法,尺取法是用于寻找一个范围,不适用与这一题。
代码如下:
public int[] twoSum(int[] nums, int target) {
int l = 0;
int r = nums.length-1;
while(l<r) {
if(nums[l]+nums[r]<target) {
l++;
}else if(nums[l]+nums[r]>target) {
r--;
}else
break;
}
return new int[] {
nums[l],nums[r]};
}
提交结果:
问题二:和为s的连续正数序列
问题描述:
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
解题思路:
这题求的是一个序列,可以看作一个范围;所以可以使用尺取法进行解题。
有关尺取法的讲解可以参考文章:尺取法
代码实现:
public static int[][] findContinuousSequence(int target) {
if(target<3) return new int[0][0];
int end = target/2 +1;
List<int[]> list = new ArrayList<int[]>(); //用于存储结果集
int l = 1;
int r = 2;
while(l<r && r<=end) {
//注意r是可以等于end的。
if(sum(l,r)>target) {
l++;
}else if(sum(l,r)<target) {
r++;
}else {
//将找到的序列封装成数组
int[] temp = new int[r-l+1];
int index = 0;
for(int i=l; i<=r; i++)
temp[index++] = i;
list.add(temp);
l++;
}
}
//将list转换为二维数组
int[][] res = new int[list.size()][];
for(int i=0; i<list.size(); i++) {
res[i] = list.get(i);
}
return res;
}
//求l 到 r 的整数序列的和
private static int sum(int l, int r) {
int s = 0;
for(int i=l; i<=r; i++) {
s += i;
}
return s;
}
提交结果:
这题可以优化一下:用等差数列求和公式进行求和:
//求l 到 r 的整数序列的和
private static int sum(int l, int r) {
int s = 0;
s = (l+r)*(r-l+1)/2;
return s;
}