代码随想录算法训练营第七天| LeetCode454.四数相加II、LeetCode383. 赎金信、LeetCode15. 三数之和、LeetCode18. 四数之和

#LeetCode 454. 4 Sum II

#LeetCode 454. 视频讲解:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili

解题思路类似Two Sum 题目,区别在于哈希映射的(key, value) 分别代表什么。将a 和b 相加,c 和d 相加后遍历,相比于暴力解决方法的n^{4} ,这样的时间复杂度为n^{2}。类似求两个数的和为0,将a 和b 的和映射在哈希数组中,因为此题不需要去除重复值,所以用value 来保存a + b的和出现的次数,如果遇到- (a + b) 的值出现在(c + d) 中,则出现value 个符合条件的值。

HashMap 的put (key, value) 方法如果遇到key 存在,则将替换旧值为新值。如果key 不存在,将插入新的键值对。HashMap 的getOrDefault(key, default) 可以获取key 键对应的值,如果key 键不存在则返回default 值。

HashMap方法:时间复杂度O(n^{2}).

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        if (nums1.length == 0 || nums2.length == 0 ||
         nums3.length == 0 || nums4.length == 0) {
             return 0;
        }
        HashMap sum = new HashMap<>();
        int ab = 0, count = 0;
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int mid_temp = nums1[i] + nums2[j];
                sum.put(mid_temp, sum.getOrDefault(mid_temp, 0) + 1);
            }
        }
        for (int i = 0; i < nums3.length; i++) {
            for (int j = 0; j < nums4.length; j++) {
                int temp = nums3[i] + nums4[j];
                count += sum.getOrDefault(-temp, 0);
            }
        }
        return count;
    }
}

#LeetCode 383. Ransom Note

#LeetCode 383. 文字讲解:代码随想录

 类似Anagram题目,用一个哈希数组来记录出现过的字母。如果ransom note 用哈希数组记录,减去magazine 上面的字母,如果哈希数组中依然有> 0 的元素则代表,magazine 上面的字母不能抵消ransom note 的需要,则返回false 。

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if (ransomNote.length() > magazine.length()) {
            return false;
        }
        int[] hash = new int[26];
        for (int i = 0; i < ransomNote.length(); i++) {
            hash[ransomNote.charAt(i) - 'a']++;
        }
        for (int j = 0; j < magazine.length(); j++) {
            hash[magazine.charAt(j) - 'a']--;
        }
        for (int k: hash) {
            if (k > 0) {
                return false;
            }
        }
        return true;
    }
}

#LeetCode 15. 3 Sum

#LeetCode 15. 视频讲解: 梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili

题目限制:Notice that the solution set must not contain duplicate triplets.

首先使用Arrays.sort() 排序,题目不要求返回下标,所以可以使用排序后的数组完成。方法是:使用双指针遍历,其中一个i 遍历整个数组,作为第一个数字,left 指针指向i 的下一位,作为第二个数字,right 指针指向数组最后一个元素,作为最后一个数字,是在找nums[i] 与那两个数字相加为0 。判断指针移动的标准是三数之和sum 与目标和0 比较,如果sum > 0,则向左移动right 指针(左边的数字小于右边数字),如果sum < 0,则向右移动left 指针,来调整sum ,前提是left < right ,如果left = right 时,则变成了2 数之和,不满足题意。

去除重复:用当前元素与前一个元素比较(因为与前一个元素比较,所以限制i > 0),如果相等则代表已经出现过,则continue 跳过此次循环。在选出三个数值后再对left 指针和right 指针去重,如果left 指针(right 指针)指向的元素与下一个元素相同,那么直接移动到下一个元素,即跳过了相同值,达到去除重复的目的。

双指针方法:

class Solution {
    public List> threeSum(int[] nums) {
        List> result = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (nums[0] > 0) {
                return result;
            }
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i + 1;
            int right = nums.length - 1;
            int sum;
            while (left < right) {
                sum = nums[i] + nums[left] + nums[right];
                if (sum < 0) {
                    left++;
                }
                else if (sum > 0) {
                    right--;
                }
                else {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    right--;
                    left++;
                }
            } 
        }
        return result;
    }
}

#LeetCode 18. 4 Sum

#LeetCode 18. 视频讲解: 难在去重和剪枝!| LeetCode:18. 四数之和_哔哩哔哩_bilibili

与四数之和为0 题目的区别,题目要求unique ,则需要去除重复数组。

剪枝操作:如果当前元素大于0 (e.g. [-4, -1, -1, 1] target = -5,如果不限制大于0 ,这个结果会被跳过)且大于目标值target ,则返回当前已经保存的result ,如果第一个元素大于0 且大于目标值target ,则返回空result 。

去重操作:与三个数之和相同。

双指针方法:

class Solution {
    public List> fourSum(int[] nums, int target) {
        List> result = new ArrayList<>();
        Arrays.sort(nums);
        for (int k = 0; k < nums.length; k++) {
            if (nums[k] > target && nums[k] > 0) {
                return result;
            }
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
            for (int i = k + 1; i < nums.length; i++) {
                if (i > k + 1 && nums[i] == nums[i - 1]) {
                    continue;
                }
                int left = i + 1;
                int right = nums.length - 1;
                while (left < right) {
                    long sum = nums[k] + nums[i] + nums[left] + nums[right];
                    if (sum > target) {
                        right--;
                    }
                    else if (sum < target) {
                        left++;
                    }
                    else {
                        result.add(Arrays.asList(nums[k], 
                        nums[i], nums[left], nums[right]));
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return result;
    }
}

你可能感兴趣的:(算法)