LeetCode_哈希表
- 15.三数之和
- 1.题目描述
- 2.双指针法
- 2.1思路及注意点
- 2.2代码实现
- 3.哈希法(有待修正)
- 3.1 思路
- 3.2 代码实现
- 18.四数之和
- 1. 题目描述
15.三数之和
1.题目描述
详情leetcode链接
2.双指针法
2.1思路及注意点
- 将数组排序,有一层for循环,i从下标0开始,同时定义一个下标left在i+1的位置上,定义下标right在数组末尾位置。
- 依次在数组中找到abc,使得a + b +c =0,这里相当于 a =nums[i],b = nums[left],c = nums[right]。
- 若nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
- 若nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left向右移动,才能让三数之和大一些,直到left与right相遇为止。
去重注意:
因为本题要求不能重复的三元组,所以需要对每个数进行去重。
最外层for循环对a去重时,错误写法:if条件为nums[i]=nums[i+1],这样判断的是结果集中是否有重复元素,会误跳过结果集
正确写法:if条件为nums[i]=nums[i-1],举例{-1,-1,2}
b和c去重时,应该在找到一个三元组后进行去重
2.2代码实现
/**
* 双指针法:(推荐)
* 思路:
* 将数组排序,有一层for循环,i从下标0开始,同时定义一个下标left在i+1的位置上,定
* 义下标right在数组末尾位置,依次在数组中找到abc,使得a + b +c =0,这里相当于 a =
* nums[i],b = nums[left],c = nums[right]。
* 若nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是
* 排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
* 若nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left向右移
*动,才能让三数之和大一些,直到left与right相遇为止。
*
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
* */
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);//对结果集进行排序
for (int i = 0; i < nums.length; i++) {
//因为对结果集进行了排序,若第一个大于0,则必然不会组成规定的三元组
if (nums[i]>0){
return result;
}
// 错误去重a方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
//正确去重方法
if (i > 0 && nums[i] == nums[i-1]){
continue;
}
int left = i+1;
int right = nums.length - 1;
//边界条件考虑:若left = right,b和c相当于同一个数,不符合题意
while (right > left){
int sum = nums[i] + nums[left] + nums[right];
if (sum > 0){
right --;
}else if (sum < 0) {
left ++;
}else {
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
//当找到一个三元组后,对b和c去重
while (right > left && nums[left]==nums[left+1]) left++;
while (right > left && nums[right]==nums[right-1]) right--;
left ++;
right --;
}
}
}
return result;
}
}
3.哈希法(有待修正)
3.1 思路
- 两层for循环就可以确定 a 和b 的数值了,然后使用哈希法来确定 0-(a+b) 是否在 数组里出现过
- 因为结果数组中不包含重复的三元组,所以需要依次对三个数进行去重及对结果去重
3.2 代码实现
/**
* 暴力法:双层for循环(不推荐)
* 思路:两层for循环就可以确定 a 和b 的数值了,
* 然后使用哈希法来确定 0-(a+b) 是否在 数组里出现过,
* 因为结果数组中不包含重复的三元组,所以需要依次对三个数进行去重及对结果去重
* 此法代码编写时间复杂度高且需要去重考虑的细节很多,复杂不推荐
* 时间复杂度:O(n^2)
* 空间复杂度:O(n) //额外的set开销
*
*/
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
Set<Integer> set = new HashSet<>();
Set<Integer> filter = new HashSet<>();
for (int i = 0; i < nums.length; i++){
if (nums[i] > 0){//若数组的第一个数大于0,直接返回
return result;
}
if (i > 0 && nums[i]==nums[i-1]){//对第一个数去重
continue;
}
for (int j = i + 1; j < nums.length; j++){
if (j > i+1 && nums[j]==nums[j-1]){//对第二个数去重
continue;
}
int third = 0 - (nums[i] + nums[j]);
if (set.contains(third) && !filter.contains(nums[j])){
List<Integer> singResult = new ArrayList<>();
singResult.add(nums[i]);
singResult.add(nums[j]);
singResult.add(third);
result.add(singResult);
set.remove(third);//对第三个数去重
filter.add(third);//防止有重复的集合
}else {
set.add(nums[j]);
}
}
}
return result;
}
}