代码随想录算法训练营第7天|

第454题.四数相加II

题目链接:454. 四数相加 II - 力扣(LeetCode)
文档讲解:代码随想录 (programmercarl.com)
视频讲解:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili
解题思路:

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> plus = new HashMap<>();
        for (int i : nums1) {
            for (int j : nums2) {
                int sum = i + j;
                //遍历两个数组,记录两个数组每两个元素的和
                plus.put(sum, plus.getOrDefault(sum, 0) + 1);
                //将和放在hashmap中,如果key已存在,则value加一,不存在则使其value等于1
            }
        }
        int count = 0;
        //统计四数相加为0出现的次数
        for (int i : nums3) {
            for (int j : nums4) {
                count += plus.getOrDefault(0 - i - j, 0);
                //如果存在0-(c+d)=a+b,则count增加value
            }
        }
        return count;
    }
}


时间复杂度:O(n^2)
该题总结:这道题需要知道用那种哈希结构,在了解到用hashmap之后思路自然而然地也就出来了。

383. 赎金信

题目链接:383. 赎金信 - 力扣(LeetCode)
文档讲解:代码随想录 (programmercarl.com)
解题思路:

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if (ransomNote.length() > magazine.length()) {
            return false;
        }
        //ransomNote更长的话就不可能被magazine构成
        int[] record = new int[26];
        //创建用于记录ransomNote中每个字母出现次数的数组
        for (int i = 0; i < ransomNote.length(); i++ ) {
            record[ransomNote.charAt(i) - 'a']++;
        }
        //记录ransomNote中每个字母出现次数
        for (int i = 0; i < magazine.length(); i++) {
            record[magazine.charAt(i) - 'a']--;
        }
        //用减法计算一遍magazine中每个字母出现次数
        for (int i : record) {
            if (i > 0) {
                return false;
            }
        }
        //确定record中每个元素是否都小于零,未出现大于零的元素则说明ransomSize可由magezine组成
        return true;
    }
}


时间复杂度:O(n)
该题总结:这道题就很简单了,在做过了之前的242. 有效的字母异位词 - 力扣(LeetCode)这道题后,看一眼代码随想录上的思路,这道赎金信就没什么难度了,和字母异位词可以说是一模一样的解法。

第15题. 三数之和

题目链接:15. 三数之和 - 力扣(LeetCode)
文档讲解:代码随想录 (programmercarl.com)
视频讲解:梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili
解题思路:

class 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 (nums[i] > 0) {
                return result;
            }
            //排序后nums[i]如果大于0则无法凑成三元组
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            //当前的nums[i]如果和nums[i-1]相同的话直接进入下一个循环来去重
            int left = i + 1;
            int right = nums.length - 1;
            //初始化双指针
            while (right > left) {
                int sum = nums[i] + nums[left] + nums[right];
                //计算三数之和!!!!要放在循环中!!!!
                if (sum > 0) {
                    right--;
                    //三数之和大于0,右指针左移
                } else if (sum < 0) {
                    left++;
                    //三数之和小于0,左指针右移
                } else {
                    result.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    //三数之和为0,添加到result列表中
                    while (right > left && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    //为left所指的元素去重
                    while (right > left && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    //为right所指的元素去重
                    left++;
                    right--;
                    //三数之和为0时,双指针收缩
                }
            }
        }
        return result;
    }
}


时间复杂度:O(n^2)
该题总结:这道题就开始上难度了,不仅仅是一开始的思路想不到,而且其中的剪枝操作和去重操作更是需要耗费精力去想。

第18题. 四数之和

题目链接:18. 四数之和 - 力扣(LeetCode)
文档讲解:代码随想录 (programmercarl.com)
视频讲解:难在去重和剪枝!| LeetCode:18. 四数之和_哔哩哔哩_bilibili
解题思路:

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<>();
        if (nums.length < 4) {
            return result;
        }
        //防止数组长度小于4
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > target && target > 0) {
                return result;
            }
            //一级剪枝
            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 (right > left) {
                    //从两边向中间遍历数组
                    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]));
                        //总和等于目标值,将四个数作为一个整体添加到列表中
                        while (right > left && nums[left] == nums[left + 1]) {
                            //这里要先检查right是否大于left
                            left++;
                        }
                        //左值去重
                        while (right > left && nums[right] == nums[right - 1]) {
                            //这里要先检查right是否大于left
                            right--;
                        }
                        //右值去重
                        left++;
                        right--;
                        //找到目标值时两指针向中间收缩
                    }
                }
            }
        }
        return result;
    }
}

specially:这段代码我认为是有问题的,我不知道为什么他能过,本来这段代码在内层for循环里面是有二级剪枝操作的,但一旦做了二级剪枝就有用例过不去,我也想不明白,求助算法训练营的大佬们了已经,有答案会在评论区更新。

时间复杂度:O(n^3)
​​​​​​​
该题总结:今日重磅题目,可以说是我这7天以来做过的最重量级的题目了,完全难于设计链表,那道题只是题量大,而这道题难点在于各种细枝末节的地方,一级剪枝,一级去重,二级剪枝,二级去重,左右指针去重,一旦有一个地方的循环/判断条件没写对,整个代码就要报错,做这道题可真是费了老大的劲了,可惜最后还有个问题没弄明白,继续加油吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值