LeetCode【0016】最接近的三数之和

news2024/11/14 14:12:25

本文目录

  • 1 中文题目
  • 2 求解方法1:二分查找法
    • 2.1 思路说明
    • 2.2 Python代码
    • 2.3 复杂度分析
  • 3 求解方法2:排序 + 双指针法
    • 3.1 思路说明
    • 3.2 Python代码
    • 3.3 复杂度分析
  • 4 题目总结

1 中文题目

给一个长度为 n 的整数数组 nums 和 一个目标值 target。请从 nums 中选出三个整数,使它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在恰好一个解。

示例 :

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2)
输入:nums = [0,0,0], target = 1
输出:0
解释:与 target 最接近的和是 0(0 + 0 + 0 = 0)。

提示:

  • 3 ≤ n u m s . l e n g t h ≤ 1000 3 \leq nums.length \leq 1000 3nums.length1000
  • − 1000 ≤ n u m s [ i ] ≤ 1000 -1000 \leq nums[i] \leq 1000 1000nums[i]1000
  • − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10^4 \leq target \leq 10^4 104target104

2 求解方法1:二分查找法

2.1 思路说明

排序保证有序性,固定两个数,用二分查找找第三个数,维护一个全局最小差值,记录最接近的和。

具体思路

  • 预处理阶段:
    • 对数组进行排序,保证有序性
    • 初始化最接近和为前三个数的和
  • 外层固定处理:
    • 第一层循环固定第一个数nums[i]
    • 第二层循环固定第二个数nums[j]
    • 计算当前已固定两数之和sum_two = nums[i] + nums[j]
    • 计算需要寻找的目标值need = target - sum_two
  • 二分查找阶段:
    • 在区间[j+1, n-1]内寻找第三个数
    • 比较中间位置的值nums[mid]与need的关系
    • 根据nums[mid]与need的大小关系调整区间
    • 每次更新时计算当前三数之和与target的差值
  • 更新策略:
    • 维护全局最小差值min_diff
    • 维护最接近的和closest_sum
    • 当找到完全相等的和时直接返回
    • 当找到更小的差值时更新结果

2.2 Python代码

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        """
        使用二分查找求解最接近的三数之和
        :param nums: 输入数组
        :param target: 目标值
        :return: 最接近目标值的三数之和
        """
        # 数组排序
        nums.sort()
        n = len(nums)
        # 初始化最接近的和
        closest_sum = nums[0] + nums[1] + nums[2]
        
        # 特判:如果target小于最小三数和或大于最大三数和
        min_sum = nums[0] + nums[1] + nums[2]
        max_sum = nums[-1] + nums[-2] + nums[-3]
        if target <= min_sum:
            return min_sum
        if target >= max_sum:
            return max_sum
            
        # 固定第一个数
        for i in range(n-2):
            # 去重
            if i > 0 and nums[i] == nums[i-1]:
                continue
                
            # 固定第二个数
            for j in range(i+1, n-1):
                # 去重
                if j > i+1 and nums[j] == nums[j-1]:
                    continue
                    
                # 二分查找第三个数
                # 计算需要找的目标值
                need = target - nums[i] - nums[j]
                
                # 在[j+1, n-1]范围内二分查找
                left = j + 1
                right = n - 1
                
                # 如果范围内只有一个数,直接判断
                if left == right:
                    curr_sum = nums[i] + nums[j] + nums[left]
                    if abs(curr_sum - target) < abs(closest_sum - target):
                        closest_sum = curr_sum
                    continue
                    
                # 二分查找过程
                while left < right - 1:  # 保留两个相邻的数
                    mid = left + (right - left) // 2
                    curr_sum = nums[i] + nums[j] + nums[mid]
                    
                    # 更新最接近的和
                    if abs(curr_sum - target) < abs(closest_sum - target):
                        closest_sum = curr_sum
                        
                    # 根据大小关系调整区间
                    if curr_sum == target:
                        return target
                    elif curr_sum > target:
                        right = mid
                    else:
                        left = mid
                        
                # 检查区间内剩余的数
                # 检查left位置
                curr_sum = nums[i] + nums[j] + nums[left]
                if abs(curr_sum - target) < abs(closest_sum - target):
                    closest_sum = curr_sum
                    
                # 检查right位置
                curr_sum = nums[i] + nums[j] + nums[right]
                if abs(curr_sum - target) < abs(closest_sum - target):
                    closest_sum = curr_sum
                    
        return closest_sum

2.3 复杂度分析

  • 时间复杂度:O(n²logn)
    • 排序:O(nlogn)
    • 第一层循环:O(n)
    • 第二层循环:O(n)
    • 内层二分查找:O(logn)
  • 空间复杂度:O(logn)或O(n)
    • 排序空间:O(logn)或O(n)
    • 其他变量:O(1)

3 求解方法2:排序 + 双指针法

3.1 思路说明

先将数组排序,以便使用双指针。固定一个数,用双指针在剩余部分寻找最接近的两个数。通过比较三数之和与目标值的差值,不断更新最接近的结果

详细算法步骤:

  • 首先对数组排序,便于使用双指针和去重
  • 固定第一个数nums[i],然后使用双指针(left, right)在剩余数组中寻找最接近的两个数
  • 在遍历过程中:
    • 计算当前三数之和sum = nums[i] + nums[left] + nums[right]
    • 比较sum与target的差值,更新最接近的结果
    • 如果sum > target,right左移
    • 如果sum < target,left右移
    • 如果sum == target,直接返回target

优化策略:

  • 去重:跳过重复的第一个数
  • 剪枝:根据排序后的特性提前结束

3.2 Python代码

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        """
        最接近的三数之和
        :param nums: 输入数组
        :param target: 目标值
        :return: 最接近目标值的三数之和
        """
        n = len(nums)
        # 先对数组排序,便于使用双指针和剪枝
        nums.sort()
        # 初始化最接近和为前三个数的和
        closest_sum = nums[0] + nums[1] + nums[2]
        
        # 优化1:先判断边界情况
        # 如果target小于数组中最小的三数之和
        min_sum = nums[0] + nums[1] + nums[2]
        if target <= min_sum:
            return min_sum
            
        # 如果target大于数组中最大的三数之和
        max_sum = nums[-1] + nums[-2] + nums[-3]
        if target >= max_sum:
            return max_sum
            
        # 固定第一个数,遍历数组
        for i in range(n-2):
            # 去重:跳过重复的第一个数
            if i > 0 and nums[i] == nums[i-1]:
                continue
                
            # 优化2:当前最小和已经大于target
            # 由于数组已排序,后面的和只会更大,可以提前结束
            curr_min = nums[i] + nums[i+1] + nums[i+2]
            if curr_min > target:
                # 更新closest_sum(如果当前的最小和更接近target)
                if abs(curr_min - target) < abs(closest_sum - target):
                    closest_sum = curr_min
                break
                
            # 优化3:当前最大和小于target
            # 说明以当前数字为第一个数时,找不到比当前closest_sum更接近的和
            curr_max = nums[i] + nums[-1] + nums[-2]
            if curr_max < target:
                # 更新closest_sum(如果当前的最大和更接近target)
                if abs(curr_max - target) < abs(closest_sum - target):
                    closest_sum = curr_max
                continue
                
            # 使用双指针在剩余数组中寻找最接近的两个数
            left = i + 1  # 左指针
            right = n - 1  # 右指针
            
            while left < right:
                # 计算当前三数之和
                curr_sum = nums[i] + nums[left] + nums[right]
                
                # 如果恰好等于target,直接返回
                if curr_sum == target:
                    return target
                    
                # 更新最接近的和
                if abs(curr_sum - target) < abs(closest_sum - target):
                    closest_sum = curr_sum
                    
                # 根据curr_sum与target的关系移动指针
                if curr_sum > target:
                    # 和太大,右指针左移
                    right -= 1
                else:
                    # 和太小,左指针右移
                    left += 1
                    
        return closest_sum

3.3 复杂度分析

  • 时间复杂度:O(n²)
    • 排序:O(nlogn)
    • 主循环:O(n)
    • 双指针循环:O(n)
  • 空间复杂度分析:O(logn)或O(n)
    • 排序空间:O(logn)或O(n)
    • 其他变量:O(1)

4 题目总结

题目难度:中等
数据结构:数组
应用算法:双指针、分治法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2239422.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32WB55RG开发(3)----生成 BLE 程序连接手机APP

STM32WB55RG开发----3.生成 BLE 程序连接手机APP 概述硬件准备视频教学样品申请源码下载参考程序选择芯片型号配置时钟源配置时钟树RTC时钟配置RF wakeup时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙设置工程信息工程文件设置结果演示 概述 本项目旨…

[C++]内联函数和nullptr

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…

微软OmniParser:一切皆文档,OCR驱动智能操作

前沿科技速递&#x1f680; 微软推出的OmniParser是一种创新的框架&#xff0c;旨在将手机和电脑屏幕视为文档&#xff0c;通过OCR技术与多模态大模型实现对用户界面的深度理解和操作。OmniParser能够高效识别和提取界面中的文本信息、位置和语义&#xff0c;助力自动化操作。 …

使用 Web Search 插件扩展 GitHub Copilot 问答

GitHub Copilot 是一个由 GitHub 和 OpenAI 合作开发的人工智能代码提示工具。它可以根据上下文提示代码&#xff0c;还可以回答各种技术相关的问题。但是 Copilot 本身不能回答非技术类型的问题。为了扩展 Copilot 的功能&#xff0c;微软发布了一个名为 Web Search 的插件&am…

Rust语言在系统编程中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Rust语言在系统编程中的应用 Rust语言在系统编程中的应用 Rust语言在系统编程中的应用 引言 Rust 概述 定义与原理 发展历程 Ru…

vue+vite前端项目ci过程中遇到的问题

将项目进行ci流水线构建时&#xff0c;遇到了npm run build 构建完成后命令行不会终止的问题&#xff0c;导致了无法进行下一个步骤。如下图&#xff1a; 排查了好久找到事vite.config.js的配置出了问题&#xff0c;如图所示&#xff0c;将build下的watch改为false即可解决问…

Python 获取PDF的各种页面信息(页数、页面尺寸、旋转角度、页面方向等)

目录 安装所需库 Python获取PDF页数 Python获取PDF页面尺寸 Python获取PDF页面旋转角度 Python获取PDF页面方向 Python获取PDF页面标签 Python获取PDF页面边框信息 了解PDF页面信息对于有效处理、编辑和管理PDF文件至关重要。PDF文件通常包含多个页面&#xff0c;每个页…

企业级RAG(检索增强生成)系统构建研究

— 摘要 检索增强生成&#xff08;Retrieval-Augmented Generation&#xff0c;RAG&#xff09;技术已经成为企业在知识管理、信息检索和智能问答等应用中的重要手段。本文将从RAG系统的现状、方法论、实践案例、成本分析、实施挑战及应对策略等方面&#xff0c;探讨企业如何…

前端学习八股资料CSS(二)

更多详情&#xff1a;爱米的前端小笔记&#xff0c;更多前端内容&#xff0c;等你来看&#xff01;这些都是利用下班时间整理的&#xff0c;整理不易&#xff0c;大家多多&#x1f44d;&#x1f49b;➕&#x1f914;哦&#xff01;你们的支持才是我不断更新的动力&#xff01;找…

SAP 创建物料主数据报错:估价范围3010还没有生产式的物料帐簿

通过接口创建物料主数据&#xff08;模拟MM01&#xff09;&#xff0c;报错如图&#xff1a; 处理方案1&#xff1a;&#xff08;我的不行&#xff0c;提示已经是生产的&#xff09; 将评估范围的物料分类账设置为生产 事务码: CKMSTART - 物料分类帐的生产开始 处理方案2&a…

扫雷游戏代码分享(c基础)

hi , I am 36. 代码来之不易&#x1f44d;&#x1f44d;&#x1f44d; 创建两个.c 一个.h 1&#xff1a;test.c #include"game.h"void game() {//创建数组char mine[ROWS][COLS] { 0 };char show[ROWS][COLS] { 0 };char temp[ROWS][COLS] { 0 };//初始化数…

leetcode 148. 排序链表 中等

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&#xff1a; …

Elasticsearch中什么是倒排索引?

倒排索引&#xff08;Inverted Index&#xff09;是一种索引数据结构&#xff0c;它在信息检索系统中被广泛使用&#xff0c;特别是在全文搜索引擎中。倒排索引允许系统快速检索包含给定单词的文档列表。它是文档内容&#xff08;如文本&#xff09;与其存储位置之间的映射&…

excel-VLOOKUP函数使用/XVLOOKUP使用

多个窗口同时编辑表格&#xff0c;方便对照操作 使用开始-视图-新建窗口 将战区信息表的三列数据匹配到成交数据表上 可以使用VLOOKUP函数 有4个参数&#xff08;必须要查找的值&#xff0c; 要查找的区域&#xff0c;要返回区域的第几列数据&#xff0c;一个可选参数查找匹…

netcore 静态文件目录浏览

环境&#xff1a;Net6 string dirPath "C:\\Users\\15298\\Pictures"; var fileProvider new PhysicalFileProvider(dirPath); app.UseStaticFiles(new StaticFileOptions {FileProvider fileProvider,RequestPath new PathString(("/files")) }); // …

1Panel修改PostgreSQL时区

需求 1Panel安装的PostgreSQL默认是UTC时区&#xff0c;需要将它修改为上海时间 步骤 进入PostgreSQL的安装目录 /opt/1panel/apps/postgresql/postgresql/data打开postgresql.conf文件 修改&#xff1a; log_timezone Asia/Shanghai timezone Asia/Shanghai保存后重启…

函数式接口和stream

函数式接口&#xff08;Functional Interface&#xff09;是Java 8引入的一个新特性&#xff0c;它只有一个抽象方法的接口。这意味着你可以将一个函数式接口作为参数传递给方法&#xff0c;或者将其实现为一个lambda表达式。函数式接口的主要目的是允许你以声明性方式处理操作…

Oracle 高水位线和低-高水位线(High Water Mark Low High Water Mark)

在Oracle的逻辑存储结构中&#xff08;表空间-段-区-块&#xff09;&#xff0c;数据是存在数据段中的&#xff0c;通常一个表就是一个数据段&#xff0c;而段最终又由许多数据块组成。当数据存入数据块时&#xff0c;需要对块进行格式化&#xff0c;高水位线&#xff08;High …

科技资讯|Matter 1.4 标准正式发布,低功耗蓝牙助力其发展

连接标准联盟&#xff08;CSA&#xff09;宣布推出最新的 Matter 1.4 版本&#xff0c;引入了一系列新的设备类型和功能增强&#xff0c;有望提高包括 HomeKit 在内的智能家居生态系统之间的互操作性。 设备供应商和平台能够依靠增强的多管理员功能改善多生态系统下的用户体验&…

python练习-Django web入门

python -m pip install --user requests使用API调用请求数据 处理API响应 import requestsclass Requests:def request(self):url "https://www.toutiao.com/stream/widget/local_weather/data/?city北京"headers {"Accept": "application/json;…