题解LeetCode——两数之和
我的LeetCode代码集:https://github.com/cnamep001/LeetCode
原题链接:https://leetcode-cn.com/problems/two-sum/description/
题目描述:
思路一:利用哈希表来记录nums数组中每一个索引所对应的数字
对于这道题来说,如果题目要求我们返回的是满足条件的两个数字,而不是这两个数字所对应的索引值,那么我们完全可以先对nums数组进行一次排序,再用对撞双指针的方法求解。
根据这个思路进一步思考,我们可以用一个哈希表来记录nums数组中每一个索引对应的数字值。我们再新建一个元素值等于索引值的长度为nums.length的数组。接下来,我们就只要根据哈希表中记录的每一个索引的值的大小来对这个新创建的数组进行排序。然后再用双对撞指针的方法求解这个问题。注意,这里的对撞双指针法中比较的不应该是数组中的值,而应该是数组中的值所对应的哈希表中的值。
此方法中排序我们采用的是三路快排的方式,由于排序的时间复杂度是O(nlogn),这里的n同样是nums数组的长度,而遍历新数组的时间复杂度是O(n)级别的,因此总的时间复杂度是O(nlogn)级别的。而对于空间复杂度来说,需要一个哈希表,还需要一个用来排序的新建数组,因此空间复杂度是O(n)级别的。和思路一相比,时间复杂度得到的优化,而代价就是空间复杂度变大,这和哈希表空间换时间的思想是一致的。
实现代码:
package com.m.two_sum.solution2;
import java.util.HashMap;
public class Solution2 {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
hashMap.put(i, nums[i]);
}
Integer[] numsCopy = new Integer[nums.length];
for (int i = 0; i < numsCopy.length; i++) {
numsCopy[i] = i;
}
sort(numsCopy, hashMap);
int left = 0;
int right = numsCopy.length - 1;
while (left < right) {
if (hashMap.get(numsCopy[left]) + hashMap.get(numsCopy[right]) == target) {
result[0] = numsCopy[left];
result[1] = numsCopy[right];
return result;
} else if (hashMap.get(numsCopy[left]) + hashMap.get(numsCopy[right]) > target) {
right--;
} else {
left++;
}
}
return result;
}
private void sort(Integer[] arr, HashMap<Integer, Integer> hashMap) {
sort(arr, 0, arr.length - 1, hashMap);
}
private void sort(Integer[] arr, int left, int right, HashMap<Integer, Integer> hashMap) {
if (left > right) {
return;
}
swap(arr, left, (int) (Math.random() * (right - left + 1)) + left);
int lessThan = left;
int greaterThan = right + 1;
int i = left + 1;
while (i < greaterThan) {
if (hashMap.get(arr[i]).compareTo(hashMap.get(arr[left])) == 0) {
i++;
} else if (hashMap.get(arr[i]).compareTo(hashMap.get(arr[left])) > 0) {
swap(arr, i, greaterThan - 1);
greaterThan--;
} else {
swap(arr, i, lessThan + 1);
lessThan++;
i++;
}
}
swap(arr, left, lessThan);
sort(arr, left, lessThan - 1, hashMap);
sort(arr, greaterThan, right, hashMap);
}
private void swap(Integer[] arr, int i, int j) {
Integer temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
LeetCode解题报告:
测试代码:
package com.m.two_sum.solution2;
import java.util.HashMap;
import java.util.Map;
public class Test2 {
public static void main(String[] args) {
int [] arr = new int[]{-1, 0, 1, 2, -1, 4};
Solution2 solution2 = new Solution2();
Map<Integer,Integer> map = new HashMap<>();
int [] result = solution2.twoSum(arr,0);
for (int i = 0; i < result.length ; i++) {
map.put(result[i],arr[result[i]]);
}
System.out.println(map); // {2=1, 4=-1}
}
}
思路二:利用哈希表通过数组中的值反向查找索引
(1)设立一个HashMap,其键用以存放数组中的值,而其键所对应的值就是该键的值在数组中的索引。
(2)遍历数组nums,一个一个元素地添加进HashMap,同时寻找答案。如果当前遍历到了nums[i]这个元素,则在HashMap中寻找是否有target - nums[i]这个键,如果有则返回该键对应的索引和索引i。如果HashMap中没有target - nums[i]这个键,则将nums[i]新添加进HashMap中。
如果HashMap中已经有了nums[i]这个键,则更新其键对应的值为新的索引i,这种情况其实是相当于数组中两个不同的索引对应相同的值的情况,由于我们在前一步已经确定了nums[i] + nums[i] != target,因此我们可以放心地舍弃前一个nums[i]对应的索引值。
如果HashMap中还没有nums[i]这个键,亦将其键对应的值设为i。
在此方法中,我们只遍历了一遍整个数组,因此时间复杂度为O(n),其中n为数组nums的长度。对于空间复杂度,我们额外设立了一个哈希表用来将数组中的值反向关联到索引,而对于数组中相同的值,我们覆盖了其先进入哈希表的索引,因此空间复杂度为O(m),其中m为数组nums中存储的不同值的数量。
package com.m.two_sum.solution3;
import java.util.HashMap;
public class Solution3 {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
int[] result = new int[2];
for (int i = 0; i < nums.length; i++) {
int anotherNum = target - nums[i];
if (hashMap.containsKey(anotherNum)) {
result[0] = hashMap.get(anotherNum);
result[1] = i;
return result;
} else {
hashMap.put(nums[i], i);
}
}
return result;
}
}
LeetCode解题报告:
测试代码:
package com.m.two_sum.solution3;
import java.util.HashMap;
import java.util.Map;
public class Test3 {
public static void main(String[] args) {
int [] arr = new int[]{-1, 0, 1, 0, -1};
Solution3 solution3 = new Solution3();
Map<Integer,Integer> map = new HashMap<>();
int [] result = solution3.twoSum(arr,0);
for (int i = 0; i < result.length ; i++) {
map.put(result[i],arr[result[i]]);
}
System.out.println(map); // {0=-1, 2=1}
}
}