代码随想录算法训练营DAY7|454、383、15、18

454四数相加

题目链接:454. 四数相加 II - 力扣(LeetCode)

思路:一开始想到了哈希表,先循环三次数组后,再使用哈希表,时间复杂度为n的立方。之后在视频启发下写出了利用两个哈希表的代码。空间复杂度较高。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer,Integer> sum1=new HashMap<>();
        HashMap<Integer,Integer> sum2=new HashMap<>();
        int count=0;
        for(int i:nums1){
            for(int j:nums2){
                int target=i+j;
                sum1.put(target,sum1.getOrDefault(target,0)+1);
            }
        }
        for(int i:nums3){
            for(int j:nums4){
                int target=i+j;
                sum2.put(target,sum2.getOrDefault(target,0)+1);
            }
        }
        Set<Integer> keys=sum1.keySet();
        for(int key:keys){
            int temp=-key;
            if(sum2.containsKey(temp)){
                count+=sum1.get(key)*sum2.get(temp);
            }
        }
        return count;
    }
}
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer,Integer> sum=new HashMap<>();
        int count=0;
        for(int i:nums1){
            for(int j:nums2){
                int temp=i+j;
                sum.put(temp,sum.getOrDefault(temp,0)+1);
            }
        }
        for(int i:nums3){
            for(int j:nums4){
                if(sum.containsKey(0-i-j)){
                    count+=sum.get(0-i-j);
                }
            }
        }
        return count;
    }
}

383赎金信

题目链接:383. 赎金信 - 力扣(LeetCode)

和242类似,既可以用哈希表也可以用数组做。

哈希表

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        HashMap<Character,Integer> hm=new HashMap<>();
        for(int i=0;i<magazine.length();i++){
            char c=magazine.charAt(i);
            hm.put(c,hm.getOrDefault(c,0)+1);
        }
        for(int i=0;i<ransomNote.length();i++){
            char c=ransomNote.charAt(i);
            if(hm.containsKey(c)){
                hm.put(c,hm.get(c)-1);
                if(hm.get(c)<0) return false;
            }else{
                return false;  
            }
                        
        }
        return true;
    }
}

 数组

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] arr=new int[26];
        for(char c:magazine.toCharArray()){
            arr[c-'a']++;
        }
        for(char c:ransomNote.toCharArray()){
            arr[c-'a']--;
        }
        for(int i=0;i<arr.length;i++){
            if(arr[i]<0)return false;
        }
        return true;
    }
}

15三数之和

题目链接:15. 三数之和 - 力扣(LeetCode)

 难点在于如何排除重复元素,大致思路是先循环后二分查找。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n=nums.length;
        Arrays.sort(nums);
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        if(n<3)return null;
        for(int i=0;i<n;i++){
            if(nums[i]>0)return res;
            if(i>0&&nums[i]==nums[i-1])continue;
            int left=i+1;
            int right=n-1;
            while(left<right){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum==0){
                    res.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    while(left<right&&nums[left]==nums[left+1])left++;
                    while(left<right&&nums[right]==nums[right-1])right--;
                    left++;
                    right--;
                }else if(sum>0){
                    right--;
                }else if(sum<0){
                    left++;
                }
                
            }
        }
        return res;
    }
}

18四数之和

题目链接:18. 四数之和 - 力扣(LeetCode)

方法一:递归

定义为long,是为了防止整数溢出。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        // 先对数组进行排序
        Arrays.sort(nums);
        // 调用函数
        return nSum(nums,target,4,0);
    }
    // 对数组nums,从start索引开始,寻找n个元素使之和为target
    public List<List<Integer>> nSum(int[] nums, long target,int n,int start){
        int sz=nums.length;
        // 定义结果
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        // n至少为2,若数组长度小于n的个数则直接返回
        if(n<2||sz<n)return res;
        // basecase为2
        if(n==2){
            int lo=start,hi=sz-1;
            while(lo<hi){
                long sum=nums[lo]+nums[hi];
                long left=nums[lo];
                long right=nums[hi];
                if(sum<target){
                    // 确保lo<hi,且若lo所指的元素和上一位元素相等,则移到下一位
                    while(lo<hi&&nums[lo]==left)lo++;
                }else if(sum>target){
                    while(lo<hi&&nums[hi]==right)hi--;
                }else{
                    // 将符合条件的两个元素放到结果中
                    // Arrays.asList()将数组改成集合类型,但是会报错java.lang.UnsupportedOperationException这是由Arrays.asList() 返回的是Arrays的内部类ArrayList, 而不是java.util.ArrayList。故将其转换为Arraylist                    
                     res.add(new ArrayList<>(Arrays.asList(nums[lo],nums[hi])));
                    //  继续排除重合的元素
                     while(lo<hi&&nums[lo]==left)lo++;
                     while(lo<hi&&nums[hi]==right)hi--;
                }
            }
        }else{
            for(int i=start;i<sz;i++){
                // 对于n>2的情况,使用递归调用函数
                List<List<Integer>> subres=nSum(nums,target-nums[i],n-1,i+1);
                // 将元素加入到res中
                for(List<Integer> arr:subres){
                    arr.add(nums[i]);
                    res.add(arr);
                }
                // 排除重复元素
                while(i<sz-1&&nums[i]==nums[i+1])i++;
            }
        }
        return res;
    }
    
}

 方法二:循环加二分

注意:排除重复元素的先后,+1、-1.

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        int n=nums.length;
        Arrays.sort(nums);
        List<List<Integer>> res=new ArrayList<>();
        for(int i=0;i<n;i++){
            if(nums[i]>target&&nums[i]>0)return res;
            if(i>0&&nums[i]==nums[i-1]) continue;
            for(int j=i+1;j<n;j++){
                if(nums[i]+nums[j]>target&&nums[i]>0)return res;
                if(j>i+1&&nums[j-1]==nums[j]) continue;
                int left=j+1,right=n-1;
                while(left<right){
                    int sum=nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum==target){
                        res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        while(left<right&&nums[left]==nums[left+1])left++;
                        while(left<right&&nums[right]==nums[right-1])right--;
                        left++;
                        right--;
                    }else if(sum>target){
                        right--;
                    }else if(sum<target){
                        left++;
                    }
                }
            }
        }
        return res;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值