当前位置: 首页 > article >正文

代码随想录刷题day21|(哈希表篇)18.四数之和

目录

一、哈希表理论基础

二、题目思路及难点

三、相关算法题目

四、总结

三数之和 和 四数之和 的不同


一、哈希表理论基础

详见 代码随想录刷题day15|(哈希表篇)242.有效的字母异位词、383.赎金信-CSDN博客

二、题目思路及难点

思路:类比三数之和,只是多加一层for循环,多进行一次剪枝和去重操作,同时内层三数之和的for循环中,对 i 的剪枝和去重操作也略有不同;

PS:剪枝是指 如果此时a(nums[i])已经>0,那么三数之和不可能再>0,所以返回结果;

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

            if(nums[i] > 0){

                //数组全为正数 三数之和不可能为0

                return result;

            }//剪枝

首先外层循环for,定义变量 k 代表a,内层for循环 i 代表b,left和right分别代表c、d,并初始化为i+1、nums.length-1;那么sum=a + b + c + d=nums[k] + nums[i] + nums[left] + nums[right];

先对k(a)进行剪枝和去重,之后进入内层for,对 i(b) 进行剪枝和去重,然后初始化left、right,进入while,先判断sum和target(逻辑同三数之和),进行left、right的移动,得到一次结果后,再对c、d去重,最后更新left和right的值,这里思路同三数之和; 

对a去重时,判断:nums[k] == nums[k-1],同时保证 k > 0;

对b去重时,判断:nums[i] == nums[i-1],同时保证 i > k+1;

对c和d去重,分别判断:nums[left] == nums[left + 1]、nums[right] == nums[right - 1],如果相等,那么分别进行left++,right--;

难点

Q:一级剪枝和去重操作(对 k/a)?

A:剪枝:if(nums[k] > target && nums[k] >= 0)

target可以是正数也可以是负数,比如 -4 -1 0 0,target = -5,k=0,numks[k]=-4 > -5,如果此时break 出错,[-4,-1,0,0]是符合条件的四元组,所以只判断nums[k] > target 不全面,应当同时满足 nums[k] >= 0 保证数组中元素均为非负数;

去重:if(k > 0 && nums[k] == nums[k-1]) 

思路同三数之和;

Q:二级剪枝和去重操作(对 i/b)?

A:剪枝:if(nums[i] + nums[k] > target && nums[k] + nums[i] >= 0)

此时,将nums[i] + nums[k]看做整体,逻辑同一级剪枝;

去重: if(i > k + 1 && nums[i] == nums[i-1])

注意 i 的取值判断和三数之和里 不同;

Q:去重和剪枝的区别?返回代码?

A:剪枝中是 break,去重中是continue;

剪枝:

对于一级循环中 k来说,如果nums[k] > target 且 nums[k] ≥ 0,数组升序,则说明整个数组都没有符合条件的四元组,所以可以退出循环,返回结果,故为berak,此外一级循环中,break等价于return result; 

对于二级循环 i 来说,如果a+b> target,且a+b≥0,则说明,没有一对c+d使得a+b+c+d=target,所以break退出循环,这里指的是二级循环,所以 return result ≠ break,前者是结束程序,返回结果,后者只是退出二层循环for(i),但会接着执行外层循环for(k);

去重:

只是有重复数据,那么continue跳出本次循环,更新i/k 直到没有重复数据即可;

Q:去重和剪枝操作是if还是while?

A:都是if;

如果是while循环,i/k值不会更新,没有条件控制语句,只有跳出本次循环,i/k值才会更新,所以不能用while,用if判断,进入下次循环后,仍会进行剪枝和去重的操作;

Q:更新left、right  和 对left、right去重的先后顺序?

A:先去重 后更新;

比如 7 7 7,while去重后,left/right会更新到最后一个相同的元素处,即上面最后一个7,然后更新,left/right+1,就会从下一个不为7的元素开始判断;

如果先更新 后去重,比如 -1 -1 0 1 2 2

left先指向第一个-1,更新后,指向第二个-1,去重条件不满足(-1 ≠ 0,但是此时left是和第一个-1相等的)从当前位置判断sum,如果right也有相同情况,则出现重复四元组,无法达到去重效果;

三、相关算法题目

18.四数之和

18. 四数之和 - 力扣(LeetCode)

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>> ();
        //对数组排序 a+b+c+d=target
        Arrays.sort(nums);
        //一级剪枝和去重
        for(int k = 0;k < nums.length;k++){
            //对a剪枝
            if(nums[k] > target && nums[k] >= 0){
                return result;
                //break;
            }
            //对a去重
            if(k > 0 && nums[k] == nums[k-1]){
                continue;
            }
            //二级剪枝和去重
            for(int i = k + 1;i < nums.length;i++){
                //对b剪枝
                if(nums[i] + nums[k] > target && nums[k] + nums[i] >= 0){
                    break;
                    //return result;
                }
                //对b去重
                if(i > k + 1 && nums[i] == nums[i-1]){
                    continue;
                }
                //判断sum 移动left和right
                int left = i + 1;
                int right = nums.length - 1;
                while(left < right){
                    int sum = nums[k] + nums[i] + nums[left] + nums[right];
                    if(sum < target){
                        left++;
                    }else if(sum > target){
                        right--;
                    }else{
                        result.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
                        //对left、right去重
                        while(left < right && nums[left] == nums[left + 1]){
                            left++;
                        }
                        while(left < right && nums[right] == nums[right - 1]){
                            right--;
                        }
                        //更新left、right
                        left++;
                        right--;
                    }
                }
            }
        }
        return result;
    }
}

四、总结

三数之和 和 四数之和 的不同

1.内层 i 的初始值不同;

2.对k的剪枝和去除(一级剪枝和去除);

3.对 i 的剪枝和去重(二级剪枝和去重);

4.注意left、right如何移动,判断、去重、更新的先后顺序;(容易搞混)


http://www.kler.cn/a/528554.html

相关文章:

  • Mysql的主从复制及扩展功能
  • 【C语言】内存管理
  • Github 2025-01-29 C开源项目日报 Top10
  • 事务03之MVCC机制
  • Agent 高频知识汇总:查漏补缺参考大全
  • android 圆形弹窗摄像头开发踩坑——源码————未来之窗跨平台操作
  • 【ubuntu】双系统ubuntu下一键切换到Windows
  • Mooncake阅读笔记:深入学习以Cache为中心的调度思想,谱写LLM服务降本增效新篇章
  • 89,[5]攻防世界 web Web_php_include
  • OpenAI o3-mini全面解析:最新免费推理模型重磅发布
  • 【SSM】Spring + SpringMVC + Mybatis
  • Unity开发游戏使用XLua的基础
  • 2024第十五届蓝桥杯网安赛道省赛题目--rc4
  • 水稻和杂草检测数据集VOC+YOLO格式1356张2类别
  • Linux tr 命令使用详解
  • 【题解】AtCoder Beginner Contest ABC391 D Gravity
  • OpenAI承认开源策略错误,考虑调整策略并推出o3-mini模型
  • 攻防世界 simple_php
  • Java基础知识总结(三十九)--流对象
  • 【JavaEE】Spring(4):配置文件
  • 1992-2025年中国计算机发展状况:服务器、电脑端与移动端的演进
  • Effective Objective-C 2.0 读书笔记—— 方法调配(method swizzling)
  • 【自然语言处理(NLP)】深度学习架构:Transformer 原理及代码实现
  • 2025_2_1 C语言中关于字符串
  • 从 HTTP/1.1 到 HTTP/3:如何影响网页加载速度与性能
  • 交易股指期货有什么技巧吗?