算法面试真题详解: 四数之和

简介: 算法面试真题详解: 四数之和

描述
给一个包含n个数的整数数组S,在S中找到所有使得和为给定整数target的四元组(a, b, c, d)。
四元组(a, b, c, d)中,需要满足a <= b <= c <= d
答案中不可以包含重复的四元组。

在线评测地址:领扣题库官网

样例 1:
输入:[2,7,11,15],3
输出:[]
样例2:
输入:[1,0,-1,0,-2,2],0
输出:
[[-1, 0, 0, 1]
,[-2, -1, 1, 2]
,[-2, 0, 0, 2]]

算法:DFS / 双指针

DFS:
朴素DFS,对排序后的队列进行搜索每次选取当前数后的比当前值大的数压入List,当List大小为4的时候判断是否四个元素的和为taeget
对数组排序
用List记录选取的元素
由于已经升序排列,只需要要去找上个元素的后面的位置的元素作为下一个元素
若List大小为4,且和为target的时候记录一次答案

复杂度分析

时间复杂度O(n^3)
最差情况搜索为n^3
空间复杂度O(n*n)
存储答案的大小
双指针:
虽然题目是四数之和,但是我们可以将他转换为三数之和,再进一步就是二数之和,先进行稳定排序,然后我们准备用四个指针
先用将问题看待为三数之和,即一个指针和三个指针
再将这三个指针看成二数之和,即一个指针和两个指针
那么问题就被化简了,先框定两个指针,再在这个基础上,用双指针解决问题,当头指针和尾指针的元素之和大于new_target,尾指针-1(因为头指针+1的结果肯定大于new_target),同理当头指针和尾指针的元素之和小于new_target,头指针+1。
对序列排序,用一个set存储答案,因为有可能存在相同的答案
用两个for循环嵌套,代表第一二个指针
然后用一对双指针从第二个指针后面的位置向右和末尾向左进行移动
如果四个指针的和等于target,将这组答案添加,如果小于的话左指针右移,反之右指针左移
将set中的答案输出

复杂度分析

时间复杂度O(n^3)
最差情况搜索为n3n3
空间复杂度 O(n^2)
存储答案的大小
//DFS

public class Solution {
    /**
     * @param numbers: Give an array
     * @param target: An integer
     * @return: Find all unique quadruplets in the array which gives the sum of zero
     */
    public List<List<Integer>> fourSum(int[] numbers, int target) {
        List<List<Integer>> ans = new ArrayList<>();
        //排序
        Arrays.sort(numbers);
        //DFS
        dfs(numbers, new ArrayList<Integer>(), target, ans, 0);
        return ans;
    }

    private void dfs(int[] numbers, List<Integer> list, int target, List<List<Integer>> ans, int index) {
        //判断值是否符合要求
        if (list.size() == 4) {
            if (target == 0) {
                ans.add(new ArrayList<Integer>(list));
            }
            return;
        }
        for (int i = index; i < numbers.length; i++) {
            if (i != index && numbers[i] == numbers[i-1]) {
                continue;
            }
            //选取当前元素
            list.add(numbers[i]);
            dfs(numbers, list, target-numbers[i], ans, i+1);
            list.remove(list.size() - 1);
        }
    }
}
//双指针
public class Solution {
    /**
     * @param numbers: Give an array
     * @param target: An integer
     * @return: Find all unique quadruplets in the array which gives the sum of zero
     */
    public List<List<Integer>> fourSum(int[] numbers, int target) {
        Set<List<Integer>> res = new HashSet<List<Integer>>();//用set可以避免出现重复答案
        Arrays.sort(numbers);
        int size = numbers.length;
        List<List<Integer>> ans=new ArrayList<List<Integer>>();
        for (int i = 0; i < size - 3; i++) {//第一个指针
            for (int j = i + 1;j < size - 2;j++) {//第二个指针
                if (j > i + 1 && numbers[j] == numbers[j-1]) {
                    continue;
                }
                int left = j + 1,right = size - 1;//第三第四个指针
                while (left < right) {
                    int sum = numbers[i] + numbers[j] + numbers[left] + numbers[right];
                    if (sum == target) {//如果序列和=target,将序列添加到set中
                        List<Integer> tmp = new ArrayList<>();
                        tmp.add(numbers[i]);
                        tmp.add(numbers[j]);
                        tmp.add(numbers[left]);
                        tmp.add(numbers[right]);
                        res.add(tmp);
                        left++; //左指针向右
                        right--;//右指针向左
                    }
                    else if (sum < target) {//如果序列和比target小,左指针向右
                        left++;   
                    }     
                    else {//如果序列和比target大,右指针向左
                        right--;
                    } 
                }
            }
        }
        for (List<Integer> tmp:res) {//输出结果
            ans.add(tmp);
        }
        return ans;
    }
}

更多题解参考:九章官网solution

相关文章
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
11月前
|
算法
面试场景题:如何设计一个抢红包随机算法
本文详细解析了抢红包随机算法的设计与实现,涵盖三种解法:随机分配法、二倍均值法和线段切割法。随机分配法通过逐次随机分配金额确保总额不变,但易导致两极分化;二倍均值法优化了金额分布,使每次抢到的金额更均衡;线段切割法则将总金额视为线段,通过随机切割点生成子金额,手气最佳金额可能更高。代码示例清晰,结果对比直观,为面试中类似算法题提供了全面思路。
1792 16
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
538 16
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
197 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩在读者群中分享了关于分库分表的基因算法设计,旨在帮助大家应对一线互联网企业的面试题。文章详细介绍了分库分表的背景、分片键的设计目标和建议,以及基因法的具体应用和优缺点。通过系统化的梳理,帮助读者提升架构、设计和开发水平,顺利通过面试。
美团面试:百亿级分片,如何设计基因算法?
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
2321 2
|
机器学习/深度学习 JavaScript 算法
面试中的网红虚拟DOM,你知多少呢?深入解读diff算法
该文章深入探讨了虚拟DOM的概念及其diff算法,解释了虚拟DOM如何最小化实际DOM的更新,以此提升web应用的性能,并详细分析了diff算法的实现机制。
|
消息中间件 存储 算法
这些年背过的面试题——实战算法篇
本文是技术人面试系列实战算法篇,面试中关于实战算法都需要了解哪些内容?一文带你详细了解,欢迎收藏!

热门文章

最新文章