454. 四数相加 II | 383. 赎金信 | 15. 三数之和 | 18. 四数之和 ||【算法学习笔记】

100 阅读4分钟

454. 四数相加 II

要求是给四个数组,要求的是满足(i,j,k,l)=0的元素的数量有多少个

🍅 map解法(哈希表),即使用一个map存储前两个数组的元素之和以及它们出现的次数,然后通过判断满足题目条件的可能得出有几种满足题意的解。

要注意的是因为要快速判断是否存在与条件相符的值,并且要得到值出现的次数,所以采用map的方式来解题。还有这道题不同顺序的组合只要满足合为0,数量都会加一,也就是说组合是不去重的,那么最后返回的就应该是符合条件的valu之和。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        int count = 0;          //count用来统计符合条件的值
        Map<Integer,Integer> map1 = new HashMap<>();
        //保存a+b和它出现的次数
        for (int a: nums1) {
            for (int b: nums2) {
                int temp = (a+b);
                if (map1.containsKey(temp)) {
                    map1.put(temp,map1.get(temp)+1);
                }else
                map1.put(temp,1);
            }
        }
        //找出num3和num4符合条件的值有多少个
        for (int c: nums3) {
            for (int d: nums4) {
                int temp = c+d;
                if (map1.containsKey(0-temp)) {
                    count += map1.get(0-temp);
                }
            }
        }
        return count;
    }
}

383. 赎金信

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成

🍅 数组解法(哈希表),即使用一个集合,一个集合录入magzine数组的元素,相比较一个字符串是否能由另一个字符串组成

这道题和之前242. 有效的字母异位词这道题类似,都是采用一个哈希映射数组。要注意的是这道题采用map的方式比较耗时,因为map结构相对数组结构要更耗时一点。

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字符串总存在magazine中没有的字符
        for(int i : record){
            if(i < 0){
                return false;
            }
        }
        return true;
    }
}

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k,同时还满足 nums[i] + nums[j] + nums[k] == 0 ,并且三元组不可以重复

🍅 双指针解法,即用left和right两个指针,对数组元素进行筛选得出最后满足条件的3个元素。

要注意的是这道题用哈希表的方式太复杂,所以用双指针的方式来解决。另外双指针的思路实现比较简单,难的是3个元素中每个元素的去重。还有ArrayList的初始化最好使用List这个接口对他初始化,因为list接口的类更为广泛,要使用其他类时修改也比较方便。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> res = new ArrayList<>();     //定义二维数组
    Arrays.sort(nums);
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] > 0) {          //减枝操作
            return res;
        }
        if (i>0 && nums[i] == nums[i-1]) {        //对i下标的元素进行去重
            continue;
        }
        int left = i+1;               //定义left指针从i+1的地方开始
        int right = nums.length-1;    //定义right指针从最后一个元素开始
        while (left < right) {        //双指针不断向中间遍历,直至sum=0
            int sum = nums[i] + nums[left] + nums[right];
            if (sum > 0) {
                right--;
            }
            else if (sum<0) {
                left++;
            }
            else {
                res.add(Arrays.asList(nums[i],nums[left],nums[right]));
                while (right>left && nums[right]==nums[right-1]) right--;  //对left下标的元素进行去重
                while (right>left && nums[left]==nums[left+1]) left++;     //对right下标的元素进行去重
                right--;
                left++;
            }
        }
    }
    return res;
    }
}

18. 四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]==target,并且四元组不可以重复

🍅 双指针解法,即用left和right两个指针,对数组元素进行筛选得出最后满足条件的3个元素。

这道题和15. 三数之和类似,都是要找去重后的数组。要注意的是这道题的target不是固定等于0的,所以通过i下标的元素判断是否大于target这样的筛选是错误的。还有这道题最后一个案例的元素值较大,需用long强制转换sum,这样返回的结果才是正确的。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
    List <List<Integer>> res = new ArrayList<>(); 
    Arrays.sort(nums);
    for(int i = 0;i < nums.length;i++){
        //剪枝操作
        if (nums[i] > target && nums[i] >= 0) {
            	break; // 这里使用break,统一通过最后的return返回
        }
        if (i > 0 && nums[i] == nums[i-1]) {    //去重操作
                continue;
        }
        for(int j = i+1;j < nums.length;j++){
            //剪枝操作
            if(nums[i]+nums[j] > target && nums[i]+nums[j] >= 0) break;
            if (j > i+1 && nums[j] == nums[j-1]) {  //去重操作
                continue;
            }
            //双指针操作
            int left = j+1;
            int right = nums.length-1;
            while (left < right) {
                long sum = (long)nums[i] + nums[j] + nums[left] + nums[right];      //强制类型转换,有个案例的值太大要用long
                if (sum > target) {
                    right--;
                }
                else if (sum < target) {
                    left++;
                }
                else{
                    res.add(Arrays.asList(nums[i], nums[j], nums
                    [left], nums[right]));
                    while (right>left && nums[right]==nums[right-1]
                    ) right--;      //对right去重
                    while (right>left && nums[left]==nums[left+1]
                    ) left++;       //对left去重
                    right--;
                    left++;
                    }
                }
            }
        }
    return res;
    }
}

如果对哈希表数据结构不熟悉或者刷题没有思路的,这边推荐卡哥的网站,里面有文字讲解和视频,我也是跟着卡哥学习的。