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

一、LeetCode454. 四数相加 II

题目链接:454. 四数相加 II
由于四个数组的长度为n(1<=n<=200),如果我们用四层循环去遍历四个数组来求每种情况的和的话,时间复杂度就是O(n^4),很可能会超时。
题目给我们的条件是:
nums1[i] + nums2[j] + nums3[k] + nums4[l] = 0;
可以变化一下等式:
nums1[i] + nums2[j] = 0 - nums3[k] - nums4[l];
通过等式我们可以创建一张Map哈希表来记录nums1和nums2的每种组合及出现的次数,然后在nums3和nums4的每种组合中查询并统计0 - nums3 - nums4(即nums1+nums2)出现的次数。
代码如下:

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> map = new HashMap<>();//用来记录nums1,nums2所有组合中的和,同时记录出现的次数
        for(int i : nums1) {
            for(int j : nums2) {
                map.put(i + j, map.getOrDefault(i + j, 0) + 1);
            }
        }

        //计算剩余两个元素的和,在map中寻找是否存在和等于0的情况,同时记录次数
        int sum = 0;
        for(int i : nums3) {
            for(int j : nums4) {
                sum += map.getOrDefault(- i - j, 0);
            }
        }        
        return sum;
    }
}

map.getOrDefault(key,value)表示返回表中键key映射的值,如果不存在该映射关系,返回默认值value;
时间复杂度O(n^2)

二、LeetCode383. 赎金信

题目链接:383. 赎金信
这道题很简单,用一个长度为26的数组来表示a~z。记录字符串magazine中每个字符出现的次数,然后减去ransomNode中每个字符出现的次数。
最后判断一下数组中的每个元素,如果出现小于0的情况说明ransomNode不能有magazine中的字符组成。

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if(ransomNote.length() > magazine.length()) return false;

        int[] arr = new int[26];
        for(int i = 0; i < magazine.length(); i++) {
            arr[magazine.charAt(i) - 'a']++;
        }
        for(int i = 0; i < ransomNote.length(); i++) {
            arr[ransomNote.charAt(i) - 'a']--;
        }
        for(int i = 0; i < 26; i++) {
            if(arr[i] < 0) return false;
        }
        return true;
    }
}

时间复杂度是O(n),空间复杂度是O(1)。

三、LeetCode15. 三数之和

题目链接:15. 三数之和
利用双指针法比较简单一点。
首先对数组进行从小到大排序,然后用for循环先遍历三元组中的第一个元素,如果排序之后第一个元素大于0,说明任意三个元素之和都可能等于0(后面的元素大于等于0)。
然后定义左右两个指针,
左指针从i+1开始,右指针从数组尾部开始,同时向中间寻找三元组第二个元素,和第三个元素,找到之后还要对两个元素分别进行去重操作。
代码如下:

lass Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);//对数组进行排序

        for(int i = 0; i < nums.length; i++) {
            if(i == 0 && nums[i] > 0) {//排序后如果第一个元素大于0,那么任意三个数之和都不可能等于0
                return result;
            }
            
            if(i > 0 && nums[i] == nums[i - 1]) continue;//对三元组第一个元素进行去重

            int left = i + 1;
            int right = nums.length - 1;

            while(left < right) {
                if(nums[i] + nums[left] + nums[right] > 0) right--;
                else if(nums[i] + nums[left] + nums[right] < 0) left++;
                else {//找到符合条件的三个元素,并将他们插入三元组数组中
                    List<Integer>list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    result.add(list);
                    //对三元组第二元素进行去重
                    while(left < right && nums[left + 1] == nums[left]) left++;
                    //对三元组第三元素进行去重
                    while(left < right && nums[right - 1] == nums[right]) right--;
                    //去重后左右指针同时收缩
                    left++;
                    right--;
                }
            }
        }
        return result;

    }
}

四、LeetCode18. 四数之和

题目链接:18. 四数之和
这道题的做法跟上道题类似,不过需要用双层for循环对四元组的第一二个元素进行遍历,然后再用左右双指针进行三四元素的搜索。
代码如下:

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(i > 0 && nums[i] == nums[i - 1]) continue;

            for(int j = i + 1; j < nums.length; j++) {
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;

                int left = j + 1; 
                int right = nums.length - 1;

                while(left < right) {
                    if((long)nums[i] + nums[j] + nums[left] + nums[right]> target) right--;
                    else if((long)nums[i] + nums[j] + nums[left] + nums[right] < target) left++;
                    else {
                        List<Integer>list = new ArrayList<>();
                        list.add(nums[i]);
                        list.add(nums[j]);
                        list.add(nums[left]);
                        list.add(nums[right]);
                        result.add(list);
                        while(left < right && nums[left] == nums[left+1]) left++;
                        while(left < right && nums[right] == nums[right - 1]) right--;

                        left++;
                        right--;
                    }
                }
            }
        }
        return result;

    }
}

总结

有些题用哈希表来写反而更加复杂。

你可能感兴趣的:(Java算法题解,算法,数据结构,java,leetcode)