代码随想录刷题——day7

165 阅读5分钟

具体代码实现

454.四数相加II

题目具体位置:454.四数相加II

经典题目使用哈希表,用空间换时间。如果只是使用暴力解法的话,时间复杂度为n的4次方。时间复杂度太大。

暴力解法如下(当然是过不了的)。

  class Solution {
        public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
           int len=nums1.length;
           int count=0;
           for(int i=0;i<len;i++){
               for(int j=0;j<len;j++){
                   for(int k=0;k<len;k++){
                       for(int l=0;l<len;l++){
                           if(nums1[i]+nums2[j]+nums3[k]+nums4[l]==0)
                                count++;
                       }
                   }
               }
           }
           return count; 
        }
    }

引入哈希表!!!

  • 此题不用考虑去重元素数值,最终只需要返回次数。

  • 需要遍历的数组共计四个、为nums1到nums4。将其两两拆分,nums1、nums2组成一对,nums3~nums4组成一对。分别进行遍历。 则时间复杂度是2*n^2

    • 使用map将nums1、nums2中元素配对所有出现的和a+b进行记录,并记录出现了几次——完全有可能出现和相同的情况。

    • 遍历nums3、nums4中元素相加的情况c+d,一旦出现了c+d==-(a+b)的情况出现,count+=map.get(a+b); —— 即count加上a+b的和出现的次数。

具体代码:

  class Solution {
        public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
            //使用map,键为nums1、nums2数组元素相加的和,值为其出现的次数
            Map<Integer,Integer> map=new HashMap<>();
            //count记录nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0的次数
            int count=0;
            //遍历num1、nums2,记录
            int len=nums1.length;
            for(int i=0;i<len;i++){
                //int sum1=0;
                for(int j=0;j<len;j++){
                    //判断当前的和是否之前已经记录在map中
                    //如果已经存在,则+1
                    if(map.containsKey(nums1[i]+nums2[j])){
                        int temp=map.get(nums1[i]+nums2[j])+1;
                        map.put(nums1[i]+nums2[j],temp);
                    }
                    //如果此前没有存入,则次数为1
                    else{
                        map.put(nums1[i]+nums2[j],1);
                    }
                }
            }
            //遍历nums3、nums4数组
            for(int k=0;k<len;k++){
                for(int l=0;l<len;l++){
                    //sum2记录num3、num4数组的和
                    int sum2=nums3[k]+nums4[l];
                    //  count加上-sum2出现在map中的次数。  其实就是为了a+b+sum2==0
                    if(map.containsKey(-sum2)){
                        count+=map.get(-sum2);
                    }
                }
            }
            return count;
        }
    }

383. 赎金信

题目具体位置

383. 赎金信

思路:

判断 ransomNote 能不能由 magazine 里面的字符构成,就是看magazine中各字母出现的次数是否大于等于ransomNote中各字母出现的次数。

  1. 利用哈希表record,记录magazine中各字母出现的次数

  2. 遍历ransomNote,每取到ransomNote中一个字母,record中对应位置的次数减一。

  3. 一旦次数不够,则return false—— 无法构成。

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        //简单判断,magazine的长度小于ransomNote长度,肯定无法构成 
        if(magazine.length()<ransomNote.length()){
            return false;
        }
        //使用数组来构成哈希表 记录下magazine中各个字母出现的次数
        int[] record=new int[26];
        for(int i=0;i<magazine.length();i++){
            //index实际上对应每个'字母'  index对应的数值就是出现的次数
            int index=magazine.charAt(i)-'a';
            record[index]++;
        }
        //遍历ransomNote字符串
        for(int j=0;j<ransomNote.length();j++){
            //计算下标 ransomNote.charAt(j)-'a' 然后record对应位置数值减1
            record[ransomNote.charAt(j)-'a']--;
            //一旦数值“不够”,则无法构成,返回false
            if(record[ransomNote.charAt(j)-'a']<0)
                return false;
        }
        return true;


    }
}

15. 三数之和

题目地址:15.三数之和

惭愧,完全没有思路。这里学习卡哥思路,用于学习记录。

思路:

  • 题目:在给定数组中选取三个数构成三元组——三数之和为0 、三元组不重复(即不同的三元组之间,元素不能完全相同)

微信图片_20240201223242.jpg

具体代码:


    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> result=new ArrayList<>();
            int len=nums.length;
            //将nums数组升序排列
            Arrays.sort(nums);
            //升序排列之后如果第一个元素都大于0,那么一定找不到符合条件的三元组
            if(nums[0]>0)
                return result;
            for(int i=0;i<len;i++){
                //对a——即nums[i] 剪枝
                if(i>0 && nums[i]== nums[i-1])
                    continue;
                int left=i+1;
                int right=len-1;
                //双指针,一次性找到当前a所对应的所有符合条件的b、c
                while(left<right){
                    int sum=nums[i]+nums[left]+nums[right];
                    //sum>0证明数字过大,缩小——即right--
                    if(sum>0){
                        right--;
                    }
                    //sum<0 证明数字过小,增大—— 即left++
                    else if(sum<0){
                        left++;
                    }
                    else{
                        result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                        //很重要! 剪枝
                        while(left<right && nums[right-1]==nums[right]){right--;}
                        while(left<right && nums[left+1]==nums[left]){left++;}
                        right--;
                        left++;
                    }
                }
            }
            return result;
        }
    }

18. 四数之和

实际上跟15.三数之和相似,不同点在于:

  • 三数之和a+b+c=0 ,控制住a,然后双指针法来找b和c (期间完成各种剪枝操作)

  • 四数之和a+b+c+d=target,就是多加一层循环,通过先控制住a、b,然后再双指针来找到c、d (期间也要对应地完成各种剪枝操作)

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++) {

            // nums[i] > target 直接返回, 剪枝操作
            if (nums[i] > 0 && nums[i] > target) {
                return result;
            }

            if (i > 0 && nums[i - 1] == nums[i]) {    // 对nums[i]去重
                continue;
            }

            for (int j = i + 1; j < nums.length; j++) {

                if (j > i + 1 && nums[j - 1] == nums[j]) {  // 对nums[j]去重
                    continue;
                }

                int left = j + 1;
                int right = nums.length - 1;
                while (right > left) {
            // nums[k] + nums[i] + nums[left] + nums[right] > target int会溢出
                    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]));
                        // 对nums[left]和nums[right]去重
                        while (right > left && nums[right] == nums[right - 1]) right--;
                        while (right > left && nums[left] == nums[left + 1]) left++;

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