持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
题目:本题依然包括两个子问题。
- 输入一个递增排序的数组和一个数字
s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。 - 输入一个正整数
target,输出所有和为target的连续正整数序列(至少含有两个数)。序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
解题思路
对于第一问,有点像两数之和,所不同的是本题的序列是有序的,那除了双层循环的方法之外,我们还可以使用哈希表和双指针来解决本题。
-
哈希表,每次检查哈希表中是否存在
target-num是否已经在哈希表中,如果存在则num和target-num即为一对正确结果,遍历完序列即可,时间复杂度和空间复杂度都为。代码如下:public int[] twoSum(int[] nums, int target) { HashSet<Integer> set = new HashSet<>(); for (int num : nums) { if(!set.contains(target-num)){ set.add(num); }else { return new int[]{num, target-num}; } } return new int[0]; } -
因为数组已经有序,因此我们可用双指针的方式来得到最终结果,通过比较两个指针和和最终target的大小来决定指针的移动方向,可得代码如下:
public int[] twoSum(int[] nums, int target) { int i=0, j=nums.length-1; while(i<j){ if(nums[i] + nums[j] == target){ return new int[]{nums[i], nums[j]}; }else if(nums[i] + nums[j] > target){ j--; }else { i++; } } return new int[0]; }
对于第二问,题目要求输出的是连续正整数序列,那本题就相对容易了,最简单的方法是使用滑动窗口的方式,每次比较窗口中元素的数值和target的大小,通过大小来决定窗口的移动即可,可得代码如下:
public int[][] findContinuousSequence(int target) {
ArrayList<int[]> list = new ArrayList<>();
int value = 0;
for(int i=1,j=1;i<target;i++){
value += i;
while(value>target){
value -= j++;
}
if(value == target){
int[] res = new int[i - j + 1];
for(int m=0;m<i-j+1;m++){
res[m] = j+m;
}
list.add(res);
}
}
return list.toArray(new int[0][]);
}