随想录训练营Day7|454.四数相加II, 383. 赎金信 ,15.三数之和, 18. 4Sum

69 阅读2分钟

随想录训练营Day7|454.四数相加II, 383. 赎金信 ,15.三数之和, 18. 4Sum

标签: LeetCode闯关记


##1. 454.四数相加II ###1.1 题目

454.四数相加II

###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.