代码随想录算法训练营第七天| 454.四数相加II 、383. 赎金信、15. 三数之和、18. 四数之和

454.四数相加II 

参考文章:代码随想录 

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

解题思路:哈希法,建立一个哈希表(Hashmap),用两层for循环遍历存储第一个和第二个数组元素之和的数值作为key,若重复则value+1,再用两个for循环遍历第三个和第四个数组,得到sum,用result来记录结果个数,查询哈希表中是否存在-sum,若存在则result+=value。最后返回result。

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> table = new HashMap<>();
        for(int i=0;i<nums1.length;i++){
            for(int j=0;j<nums2.length;j++){
                int sum = nums1[i]+nums2[j];
                table.put(sum,table.getOrDefault(sum,0)+1);
            }
        }
        int result=0;
        for(int i=0;i<nums3.length;i++){
            for(int j=0;j<nums4.length;j++){
                int sum = nums3[i]+nums4[j];
                if(table.containsKey(-sum)){
                    result+=table.get(-sum);
                }
            }
        }
        return result;
    }

383. 赎金信

参考文章:代码随想录 

解题思路:

因为题目所只有小写字母,那可以采用空间换取时间的哈希策略, 用一个长度为26的数组还记录magazine里字母出现的次数。

然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。

依然是数组在哈希法中的应用。

一些同学可能想,用数组干啥,都用map完事了,其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!

public boolean canConstruct2(String ransomNote, String magazine){
        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']--;
            if(arr[ransomNote.charAt(i)]<0){
                return false;
            }
        }
        return true;
    }

15. 三数之和

参考文章:代码随想录 

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

解题思路:双指针法,首先将数组进行排序,定义三个指针i,left,right,第一个指针固定,left=i+1,right=nums.length-1,当sum值大于0时,因为sum要等于0,所以right指针要左移,同理小于0时,left右移,当等于0时,将该arraylist集存储到结果集中。

另外还需要注意不能存在重复的结果,所以需要对i=i-1,left=left+1,right=right-1这种情况另外进行判断。

当排序后,若i已经大于0的时候,可以直接返回result来进行剪枝操作。

public static List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> result =new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            int left=i+1;
            int right=nums.length-1;
            if(i>0&&nums[i]==nums[i-1]) continue;
            System.out.println(right);
            while(left<right){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum>0){
                    right--;
                }else if(sum<0){
                    left++;
                    System.out.println(left);
                }else {
                    List<Integer> list = new LinkedList<>();
                    list.add(nums[i]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    result.add(list);
                    while(right>left&&nums[right]==nums[right-1]){
                        right--;
                    }
                    while(right>left&&nums[left]==nums[left+1]){
                        left++;
                    }
                    left++;
                    right--;
                }
            }
        }
        return result;
    }

18. 四数之和

 参考文章:代码随想录

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

解题思路:

和上面三数之和是差不多的,同样是双指针法,就是多套了一层for循环,固定两个指针i,j,另外两个指针移动来找到等于target的值。 

需要注意sum值为long型,否则可能发生栈溢出的情况。 例如int[] nums = new int[]{1000000000, 1000000000, 1000000000, 1000000000},此时若target=-294967296会返回一个结果。

同样要注意不能出现重复结果,所以要判断i=i-1,j=j-1,left=left+1,right=right-1的情况。

可以进行两级剪枝操作: 

第一级:

if (nums[i] > target && target >= 0) return result;

第二级:

if(nums[i]+nums[j]>target&&nums[i]+nums[j]>0) return result;
public static 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] > 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 (left < right) {
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum > target) {
                        right--;
                    } else if (sum < 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;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值