力扣刷题Day6

454. 四数相加

题目:力扣

这道题因为没有考虑重复元素问题,因此可以考虑简单一些。

可以将数组分为两组。

A + B + C + D = 0 ==> A+B = 0 -(C+D)

用map储存A+B「key」以及出现频率「value」,然后用C+D查找是否存在A+B - 累加频率

代码实现:

 public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap map = new HashMap<>();
        for(int i=0; i

 参考资料:代码随想录

383. 赎金信

题目:力扣

解法其实和有效的分母异位词类似,使用hashmap,这里因为明确是使用magazine 来生成ransom,因此需要储存进map的字符以及频率就必须是magazine。

然后遍历ransom,如果有在map中不存在的字符则直接返回false;有存在的字符则将频率-1 ==》代表被使用;如果频率小于0,则返回false。

    public boolean canConstruct(String ransomNote, String magazine) {
        HashMap map = new HashMap<>();
        for(int i=0; i

15. 三数之和 

 第一反应是先排序;然后使用双指针,固定第一位,然后用left和right指向数组剩下的头和尾;若是和为0则保存数列;若是大于0则right向左移动 - 减小;若是小于0则left向右移动 - 增加。

整体逻辑很简单,但是注意细节:

因为需要返回不重复的list,那么就需要去重。

如何去重?

第一种方案是采用hashset - 这里注意使用Stream进行集合类型转换

public List> threeSum(int[] nums) {

        if(nums == null || nums.length < 3){
            return null;
        }
        
        Arrays.sort(nums);

        HashSet> set = new HashSet<>();

        for(int i=0; i 0) break; //剪枝
            
            int left = i+1;
            int right = nums.length -1;
            int sum = nums[i] + nums[left] + nums[right];

            

            while(left < right){
                if(sum == 0){
                    set.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    left++;
                    right--;
                }else if(sum > 0){
                    right --;
                }else{
                    left++;
                }

                sum = nums[i] + nums[left] + nums[right];
            }
        }
        
        return set.stream().toList();

        // List> result = new ArrayList<>();
        // for(List l : set){
        //     result.add(l);
        // }

        // return result;
    }

第二种方案是通过比较指针移动的数是否相同 - 这里有个细节问题不能讲三元素中存在重复元素的list忽略

也就是这个写法存在问题:

if (nums[i] == nums[i + 1]) { // 去重操作
    continue;
}

例如{-1, -1 ,2} 这组数据,当遍历到第一个-1 的时候,判断 下一个也是-1,那这组数据就pass了。 

应该这样写:

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

 当前使用 nums[i],我们判断前一位是不是一样的元素,在看 {-1, -1 ,2} 这组数据,当遍历到 第一个 -1 的时候,只要前一位没有-1,那么 {-1, -1 ,2} 这组数据一样可以收录到 结果集里。

具体代码实现:

 public List> threeSum(int[] nums) {
        List> result = new ArrayList<>();
        if(nums == null || nums.length < 3){
            return result;
        }
        
        Arrays.sort(nums);
        for(int i = 0; i < nums.length; i++){
            //第一个数大于0,那么说明三数和肯定大于0
            if(nums[i] > 0){
                break;
            }
            //如何去重
            if(i>0 && nums[i] == nums[i-1]){
                continue;
            }
            int left = i+1;
            int right = nums.length -1;
            while(left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(sum == 0){
                    result.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){
                    left++;
                }else{
                    right--;
                }
            }
        }

        return result;

    }

 参考资料:代码随想录

 18. 四数之和

 逻辑和三数之和是一样的,但是细节上需要注意:

  • 剪枝问题 -  不要判断nums[k] > target 就返回了, 四数之和这道题目 target是任意值。比如:数组是[-4, -3, -2, -1]target-10,不能因为-4 > -10而跳过。但是我们依旧可以去做剪枝,逻辑变成nums[i] > target && (nums[i] >=0 || target >= 0)就可以了。
public List> fourSum(int[] nums, int target) {
        if(nums == null || nums.length <4) return new ArrayList<>();

        Arrays.sort(nums);
        HashSet> set = new HashSet<>();

        for(int i=0; i target && nums[i] > 0) break;
            for(int j=i+1; j target) continue;

                int left = j+1;
                int right = nums.length -1;
                int sum = nums[i] + nums[j] + nums[left] +nums[right];

                while(left < right){
                    if(sum == target){
                        set.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        left++;
                        right --;
                    }else if(sum > target){
                        right --;
                    }else{
                        left++;
                    }

                    sum = nums[i] + nums[j] + nums[left] +nums[right];
                }
            }
        }

        return set.stream().toList();

    }

参考资料:代码随想录

你可能感兴趣的:(leetcode刷题,leetcode,算法,数据结构)