两数之和Ⅰ
题目描述
给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
实例1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
实例2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
实列3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示
- 2 <= nums.length <= 104
- -109 <= nums[i] <= 109
- -109 <= target <= 109
- 只会存在一个有效答案
思路
所给数组是无序的。因为只有一个答案,所以最笨的方法就是两个for循环。但如果我们用哈希表来解决,会降低时间复杂度。我们用(target - nums[i])来作为key值,i作为value值。因为最后返回的是数组下标。
为什么用(target - nums[i])来作为key值?因为要找两数之和等于target,对于每一个数,它所需要的是(target - num[i]),也就是另一个num[j]的值。如果我们发现哈希表存在num[j],即存在(target - num[i]),那么我们就直接返回value值和j。如果不存在,则把(target - num[i],i)存入到哈希表。
代码
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> hashTable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
if (hashTable.containsKey(target - nums[i])){
return new int[] {hashTable.get(target - nums[i]),i};
}
hashTable.put(nums[i],i);
}
return null;
}
两数之和Ⅱ
题目描述
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
实例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] 。
实列3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
提示
- 2 <= numbers.length <= 3 * 104
- -1000 <= numbers[i] <= 1000
- numbers 按 非递减顺序 排列
- -1000 <= target <= 1000
- 仅存在一个有效答案
思路
和上一题不一样,该题数组是非递减顺序排列,这时我们就不需要就用哈希表来操作。对于target = num[i] + num[j](i < j),如果num[i] + num[j] > target,我们希望num[i]小一点或者num[j]小一点。(num[i] + num[j] < target同理)。但这就出现两种情况,到底是num[i]小一点还是num[j]小一点(同理是num[i]大一点还是num[j]大一点)。所以我们需要固定一个,让另一个变化。我们让i从0开始,j从num.length-1开始。这样如果num[i] + num[j] > target,我们能变化的只有num[j],因为num[i]是最小的(非递减num[0]最小),所以我们让num[j]小一点,变成num[j--],以此循环。如果num[i] + num[j] < target,我们能变化的只有num[i],因为num[j]是最大的(非递减num[num.length - 1]最大),所以我们让num[i]大一点,变成num[i++],以此循环。直到我们找到 target = num[i] + num[j]。
代码
public int[] twoSum(int[] num, int target) {
int len = num.length;
int start = 0;
int end = len - 1;
while(start <= end){
int sum = num[start] + num[end];
if(sum == target){
return new int[]{start + 1, end + 1};
}else if(sum > target){
end--;
}else{
start++;
}
}
return null;
}