随想录训练营Day7|454.四数相加II, 383. 赎金信 ,15.三数之和, 18. 4Sum
标签: LeetCode闯关记
##1. 454.四数相加II ###1.1 题目
###1.2 解题思路 用HashMap存储nums1和nums2的和,并存放该和出现的次数;目的:将时间复杂度从O(n4)减少为O(n2) ###1.3 遇到问题
###1.4 算法实现
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
//计算nums1 + nums2( //统计两个数组中的元素之和,同时统计出现的次数,放入map)
HashMap<Integer,Integer> map1 = new HashMap<>();
int temp = 0;
int res = 0;
int count = 0;
for (int i :nums1) {
for (int j : nums2) {
temp = i + j;
if(map1.containsKey(temp)){
map1.put(temp, map1.get(temp) + 1);
}else{
map1.put(temp,1);
}
}
}
// //统计剩余的两个元素的和,在map1中找是否存在相加为0的情况,同时记录次数
for (int i : nums3) {
for (int j : nums4) {
temp = i + j;
res = 0 - temp;
if (map1.containsKey(res)){
count += map1.get(res);//注意这里加的是value,而不是直接count++
}
}
}
return count;
}
}
注意点:判断何时用hashmap
###1.5 题目总结
解题耗时:40min ###1.6 相关题目
##2. 383. 赎金信 ###2.1 题目 383. 赎金信 ###2.2 解题思路 字母---数组 ###2.4 实现代码
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] record = new int[26];
for (int i = 0; i < magazine.length(); i++){
record[magazine.charAt(i) - 'a']++;
}
for (int j = 0; j < ransomNote.length(); j++) {
record[ransomNote.charAt(j) - 'a']--;
if(record[ransomNote.charAt(j) - 'a'] < 0){
return false;
}
}
return true;
}
}
###2.5 题目总结 解题耗时: 40min ###2.6 相关题目
##3. 15.三数之和 ###3.1 题目 相关链接 15.三数之和
###3.2 解题思路 方法1:哈希法(没看懂怎么去重) ①先从小到大排序; ②两次for循环找到去重后的三元组的元素a和元素b,并算出应该找到的元素c
- 元素c不在hashset中,则将遍历得到的元素b放入hashset;
- the hashset contains 元素c,则找到一组三元组;
方法2:左右指针(重点:去重的细节)
①先从小到大排序;
②nums[i]作为三元组的元素a;注意点:-对a去重;
③左右指针,看sum与0的关系对应左右指针的走向;注意点:找到符合条件sum = 0的一组三元组后,对元素b,c进行去重;
###3.3 遇到问题 无 ###3.4 算法实现
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
//排序nums
Arrays.sort(nums);
//遍历数组
for (int i = 0; i < nums.length; i++) {
if(nums[i] > 0){
return result;
}
//去重a
if(i > 0 && nums[i] == nums[i-1]){ //i > 0 防止i出现负数 //cf: nums[i] == nums[i+1]
continue;//continue语句的作用是跳过当前迭代,直接进入下一次迭代。也就是说,如果当前if条件满足,程序会直接跳过本次循环中的剩余语句,执行下一次循环,而不是退出整个循环。这样可以达到去重的目的,即当数组中的相邻两个数相等时,只考虑第一个数,跳过后面的数。
}
int left = i + 1;
int right = nums.length - 1;
int sum = nums[i] + nums[left] + nums[right];
while(left < right){
if(sum > 0){
right --;
}else if(sum < 0){
left ++;
}else{
result.add(Arrays.asList(nums[i], nums[left], nums[right]));//Arrays.asList()方法是Java中Arrays类的一个静态方法,它接受一个数组作为参数,将该数组转换为List集合
//去重元素b,c
if(nums[left] == nums[left+1]){
left ++;
}
if(nums[right] == nums[right-1]){
right --;
}
//移动左右指针
left++;
right--;
}
}
}
return result;
}
}
###3.5 题目总结 解题耗时:65min ###3.6 相关题目
##4. 18. 4Sum ###4.1 题目 相关链接 18. 4Sum
###4.2 解题思路
###4.3 遇到问题 java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 6
###4.4 算法实现
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
//排序
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
//第一次剪枝
if(nums[i] > 0 && nums[i] > target){
return result;
}
//第一次去重
if(i > 0 && nums[i -1] == nums[i]){
continue;
}
for (int j = i + 1; j < nums.length; j++) {
//第二次剪枝
if(nums[j] +nums[i] > target && nums[j] > 0){
return result;
}
//第二次去重
if(j > i + 1 && nums[j - 1] == nums[j]){
continue;
}
//通过左右指针找到元素c,d
int left = j + 1;
int right = nums.length - 1;
/*
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
若放在这个位置会出现ArrayIndexOutOfBoundsException报错,不是很懂为什么出现报错
*/
while (left < right){
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum > target){
right--;
}else if (sum < target){
left++;
}else{
result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
//第三次去重
if(nums[left] == nums[left + 1]){
left++;
}
if (nums[right] == nums[right - 1]){
right--;
}
left++;
right--;
}
}
}
}
return result;
}
注意点:剪枝和去重
###4.5 题目总结 解题耗时:70min ###4.6 相关题目
##5. 今日心得 三数之和和四数之和的去重有点难,需要注意好多细节.将这题和两数之和用hashmap做对比. 补3.21.