代码随想录算法训练营第七天|哈希表454、383、15、18
文章目录
LeetCode 454.四数相加Ⅱ
解题思路:a+b=0-(c+d),先使用a+b构建map,之后在map中找-(c+d)
难点:两两相加的思路重要
代码如下:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer, Integer> map = new HashMap<>();
int temp;
int res = 0;
//统计两个数组中的元素之和,同时统计出现的次数,放入map
for (int i : nums1) {
for (int j : nums2) {
temp = i + j;
if (map.containsKey(temp)) {
map.put(temp, map.get(temp) + 1);//map.get(temp)获取temp原有value,即次数
} else {
map.put(temp, 1);
}
}
}
//统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数
for (int i : nums3) {
for (int j : nums4) {
temp = i + j;
if (map.containsKey(0 - temp)) {
res += map.get(0 - temp);
}
}
}
return res;
}
}
LeetCode 383.赎金信
解题思路:此题使用哈希数组的方法做,类似于两数相交,如果数组中存在负数,说明ransomNote字符串减多了,即ransomNote中有magazine没有的字符
难点:magazine.toCharArray() 字符串转为字符数组
代码如下:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
//此题用哈希数组较为简便
int[] record = new int[26];
for(char c : magazine.toCharArray()){
record[c - 'a']+=1;
}
for(char c : ransomNote.toCharArray()){
record[c - 'a']-=1;
}
// 如果数组中存在负数,说明ransomNote字符串减多了,即ransomNote中有magazine没有的字符
for(int i : record){
if(i < 0){
return false;
}
}
return true;
}
}
LeetCode 15.三数之和***
思路:采用双指针的方法,要对i可能会指向值相同的数字进行去重 if(i > 0 && nums[i] == nums[i-1]) continue; 之后去重逻辑应该放在找到一个三元组之后,对b 和 c去重
难点:两次去重的思路较难想到,代码书写中要熟悉while的使用,以及Arrays.sort(),以及List中的一些函数
代码如下:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);//对nums进行排序
for(int i = 0;i < nums.length;i++){
if(nums[i] > 0){
return result;
}
//紧接着对i可能会指向值相同的数字进行去重
if(i > 0 && nums[i] == nums[i-1]) continue;
int left = i + 1, right = nums.length - 1;
while(left < right){
if(nums[i] + nums[left] + nums[right] < 0){
left++;
}else if(nums[i] + nums[left] + nums[right] > 0){
right--;
}else if(nums[i] + nums[left] + nums[right] == 0){//此处注意对结果去重
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
//此处用while是接续判断,或许有很多重复
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
right--;
left++;
}
}
}
return result;
}
}
LeetCode 18.四数之和
思路:在三数之和的基础上再套一个for循环
难点:要二重剪枝,二重去重,// nums[k] + nums[i] + nums[left] + nums[right] > target int会溢出
long sum = (long) nums[k] + nums[i] + nums[left] + nums[right];
代码如下:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for(int k=0;k < nums.length;k++){
if(nums[k] > 0 && target > 0 && nums[k] > target){//剪枝
return result;
}
if(k > 0 && nums[k] == nums[k-1]){//去重
continue;
}
for(int i = k+1;i < nums.length;i++){
if(nums[i] > 0 && target > 0 && (nums[k]+nums[i]) > target){//剪枝,必不可能等于target
break;
}
if(i > (k+1) && nums[i] ==nums[i-1]){//去重,此处i初值为k+1,因此i要至少为k+2才能出现nums[i-1]
continue;
}
int left = i + 1, right = nums.length - 1;
while(left < right){//此处为双指针法的循环条件,不要忘记
// nums[k] + nums[i] + nums[left] + nums[right] > target int会溢出
long sum = (long) nums[k] + nums[i] + nums[left] + nums[right];
if(sum > target){
right--;
}else if(sum < target){
left++;
}else if(sum == target){
result.add(Arrays.asList(nums[k],nums[i],nums[left],nums[right]));
//去重c d
while(left < right && nums[right]==nums[right-1]) right--;
while(left < right && nums[left]==nums[left+1]) left++;
left++;
right--;
}
}
}
}
return result;
}
}
总结
常见的三种哈希结构:
- 数组
- set(集合)
- map(映射)
明确什么时候数组作为哈希表,什么时候集合作为哈希表
说一说:使用数组和set来做哈希法的局限。
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
map是一种<key, value>
的结构,本题可以用key保存数值,用value在保存数值所在的下标。所以使用map最为合适。
- 四数之和,15.三数之和都推荐使用双指针法!需要去重操作!