代码随想录算法训练营day7|哈希表day2

题目链接🔗:
454.四数相加II
383. 赎金信
15. 三数之和
18. 四数之和

只讨论 hash 的做法

四数相加 II

要用哈希表,明确要存储的键值对分别是什么,键就是数组中元素的值,值就是这个值出现的次数。四个数组分成两部分,每一部分有两个数组循环,时间复杂度是最低的,所以用nums1和nums2每个元素的和相加作为键,存到哈希表中,如果存在就将原来的值加一,没有就添加值为 1 的键值对。

// 向哈希表中添加键值对,如果存在就+1,没有置 1
countAB.put(i + j, countAB.getOrDefault(i + j, 0) + 1); 

之后将nums3和nums4做循环,用这两个数组的元素之和查询target-nums3[i] - nums4[j]的键值对是否存在,存在就将值加到要返回的结果中。

赎金信

遍历代表杂志的字符串,用数组统计每个字母出现的次数。之后遍历写赎金信需要的字符串,每次遇见需要的字母就减一,如果出现小于 0 的情况说明无法构成赎金信,返回 false 。遍历结束没有返回就返回 true 。

三数之和

这道题目因为有没有重复数值的限制,所以用哈希表并不是很好做。首先一定要排序,不排序没法做 排序是为了去重,而且对于在前后顺序不同的元素,有不同的去重方法。

// 对于第一个元素使用的是
if (nums[i] == nums[i + 1] {
	continue; // 在这种情况下每次的第一个元素都应该是排序后的重复元素中的第一个
}

// 对于第二个元素
// 为什么要从第三个也就是j + 3开始呢,
// 因为假设从j + 2开始就会漏掉 [0,0,0]这种特殊的情况
if (j > 2 && nums[j] == nums[j - 1] && nums[j - 1] == nums[j - 2]) {
			continue;
}

// 对于第三个元素的去重 从set中得到结果后,移除这个元素,
// 这样后边相同的键就查询不到
if (set.contains(-nums[i] - nums[j])) {
	result.add(Arrays.asList(nums[i], nums[j], -nums[i]-nums[j]));
}

因为这次没有统计次数,所以直接使用 HashSet 即可。
上述是代码随想录给出的题解,我的方法是用的 HashMap,记录的是每个数组元素的大小和对应的下标。
当然数组也是需要排序之后,将每个元素加入到 Map 当中,之后开始两重循环,就是查 Map 当中是否有两个数组的元素的和的相反数,并且要求得到的值,也就是这个相反数在数组中的下标要大于第二层循环的j,这样可以保证有序性,也就是为了去重。
之后因为数组是在排序之后将每个元素加入到 Map 的,所以 Map 当中存储的都是每个数值所对应的数组下标的最后一个,因为数组从前向后添加,后边的数值刷新的前边的数值。所以对两次循环中的i和j都更新到当前的数值的最后一位。
i = map.get(nums[i]);
这样在下一次循环,i,j分别加一之后就更新到下一个新的值了(也就是重复数值的数组的第一个下标)
当然,用双指针更好这题目。

四数之和

和三数之和相同。

总结

单独的 hash 题目还是比较少,更多是作为思想和工具体现,只用hash确实挺费劲的。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值