第七天:今天题目都不简单,四数之和II可以再看看

文章详细介绍了使用Java解决四类经典的算法问题:四SumII通过构建哈希表来计算两数组元素和的出现次数,RansomNote判断ransomNote是否能由magazine中的字符组成,3Sum和4Sum采用双指针法找到数组中和为目标值的所有三元组和四元组。
  1. 4Sum II

这题经典而且不简单。Map对应的是前两个数组的各个元素两数之和以后需要的另两个数组的和map该和出现的次数。
后面再求另外两个数组的和时,只需要看map里是否有,有多少”需要“的和元素,并加其所有的可能性即可。

class Solution {
    Map<Integer, Integer> map = new HashMap<>();

    private void findSum(int[] nums1, int[] nums2){
        int len1 = nums1.length;
        int len2 = nums2.length;

        for(int i = 0; i < len1; ++i){
            for(int j = 0; j < len2; ++j){
                int sum = -nums1[i] - nums2[j];
                map.merge(sum, 1, Integer::sum); //意思:如果不存在sum,建立sum map到1;如果已经存在sum,++当前sum。
            }
        }
    }

    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        int count = 0;
        int len1 = nums3.length;
        int len2 = nums4.length;

        findSum(nums1, nums2);

        for(int i = 0; i < len1; ++i){
            for(int j = 0; j < len2; ++j){
                int sum = nums3[i] + nums4[j];
                if(map.containsKey(sum)){
                    count += map.get(sum);
                }
            }
        }

        return count;
    }
}

2.Ransom Note
简单题

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] arr = new int[26];
        int len = magazine.length();
        int len2 = ransomNote.length();

        for(int i = 0; i < len; ++i){ 
            ++arr[magazine.charAt(i) - 'a'];
        }

        for(int i = 0; i < len2; ++i){
            int idx = ransomNote.charAt(i) - 'a';
            --arr[idx];
            if(arr[idx] < 0) return false;
        }
        return true;
    }
}
  1. 3Sum

双指针做法,没有剪枝,也懒得优化了。正确答案和这个应该大差不离。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        int len = nums.length;

        for(int i = 0; i < len-2; ++i){
            int left = i+1, right = len-1;
            while(left < right){
                while(left < right && nums[left] + nums[right] + nums[i] > 0) --right;
                while(left < right && nums[left] + nums[right] + nums[i] < 0) ++left;
                if(left < right && nums[left] + nums[right] + nums[i] == 0){
                    List<Integer> tmp = new ArrayList<>();
                    tmp.add(nums[left]); tmp.add(nums[right]); tmp.add(nums[i]); res.add(tmp);
                    while(left < right && nums[right] == nums[right-1]) {
                        --right;
                        continue;
                    }
                    --right;
                    continue;
                }
            }
            while(i < len-2 && nums[i] == nums[i+1]) ++i;
        }
        return res;
    }
}
  1. 4Sum
    这题是真的难写啊…很多edge cases要考虑,并且我借鉴了代码随想录《三数之和》 的写法。整体不难,但很折磨人。

     class Solution {
         public List<List<Integer>> fourSum(int[] nums, int target) {
             Arrays.sort(nums);
             List<List<Integer>> res = new ArrayList<>();
             int len = nums.length;
     
             for(int i = 0; i < len-3; ++i){
                 while(i > 0 && i < len-3 && nums[i] == nums[i-1]) ++i;
                 for(int j = i+1; j < len-2; ++j){
             
                     while(j < len-2 && i != j-1 && nums[j] == nums[j-1]) ++j;
                     int left = j+1, right = len-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{
                             res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                             while(left < right && nums[left+1] == nums[left]) {++left;}
                             while(left < right && nums[right] == nums[right-1]) {--right;}
                             ++left; --right;
                         }
                     }
                 }
             }
     
             return res;
         }
     }
    
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值