二分查找 | 绝对差值和

题目:1818. 绝对差值和

给你两个正整数数组 nums1nums2 ,数组的长度都是 n

数组 nums1nums2绝对差值和 定义为所有 |nums1[i] - nums2[i]|0 <= i < n)的 总和下标从 0 开始)。

你可以选用 nums1 中的 任意一个 元素来替换 nums1 中的 至多 一个元素,以 最小化 绝对差值和。

在替换数组 nums1 中最多一个元素 之后 ,返回最小绝对差值和。因为答案可能很大,所以需要对 109 + 7 取余 后返回。

|x| 定义为:

  • 如果 x >= 0 ,值为 x ,或者
  • 如果 x <= 0 ,值为 -x

示例 1:

输入:nums1 = [1,7,5], nums2 = [2,3,5]
输出:3
解释:有两种可能的最优方案:
- 将第二个元素替换为第一个元素:[1,7,5] => [1,1,5] ,或者
- 将第二个元素替换为第三个元素:[1,7,5] => [1,5,5]
两种方案的绝对差值和都是 |1-2| + (|1-3| 或者 |5-3|) + |5-5| = 3

示例 2:

输入:nums1 = [2,4,6,8,10], nums2 = [2,4,6,8,10]
输出:0
解释:nums1 和 nums2 相等,所以不用替换元素。绝对差值和为 0

示例 3

输入:nums1 = [1,10,4,4,2,7], nums2 = [9,3,5,1,7,4]
输出:20
解释:将第一个元素替换为第二个元素:[1,10,4,4,2,7] => [10,10,4,4,2,7]
绝对差值和为 |10-9| + |10-3| + |4-5| + |4-1| + |2-7| + |7-4| = 20

提示:

  • n == nums1.length
  • n == nums2.length
  • 1 <= n <= 105
  • 1 <= nums1[i], nums2[i] <= 105

解题思路

  • 题目核心:通过替换 nums1 中的一个元素,使得 nums1nums2 之间的绝对差值和最小化。

  • 二分查找实现步骤:

    1. 计算初始绝对差值和
    2. nums1排序
    3. 遍历nums1并尝试替换每个元素
      • 二分查找找到最接近 nums2[i] 的值
      • 检查 pospos-1 位置的值
    4. 取模并返回结果

暴力解法(超时)

from typing import Listclass Solution:def minAbsoluteSumDiff(self, nums1: List[int], nums2: List[int]) -> int:MOD = 10**9 + 7n = len(nums1)# 计算初始的绝对差值和initial_sum = sum(abs(nums1[i] - nums2[i]) for i in range(n))min_sum = initial_sum# 尝试替换 nums1 中的每个元素for i in range(n):current_diff = abs(nums1[i] - nums2[i])# 遍历 nums1 中的每个元素作为替换候选for j in range(n):if i != j:new_diff = abs(nums1[j] - nums2[i])new_sum = initial_sum - current_diff + new_diffmin_sum = min(min_sum, new_sum)return min_sum % MOD# 示例测试用例
solution = Solution()
print(solution.minAbsoluteSumDiff([1, 10, 4, 4, 2, 7], [9, 3, 5, 1, 7, 4]))  # 应输出:20

二分查找

from bisect import bisect_left
from typing import Listclass Solution:def minAbsoluteSumDiff(self, nums1: List[int], nums2: List[int]) -> int:MOD = 10**9 + 7n = len(nums1)sorted_nums1 = sorted(nums1)# 初始绝对差值和initial_sum = sum(abs(nums1[i] - nums2[i]) for i in range(n))min_sum = initial_sumfor i in range(n):current_diff = abs(nums1[i] - nums2[i])# 二分查找找到最接近 nums2[i] 的值pos = bisect_left(sorted_nums1, nums2[i])# 检查 pos 位置的值if pos < n:new_diff = abs(sorted_nums1[pos] - nums2[i])new_sum = initial_sum - current_diff + new_diffmin_sum = min(min_sum, new_sum)# 检查 pos-1 位置的值if pos > 0:new_diff = abs(sorted_nums1[pos - 1] - nums2[i])new_sum = initial_sum - current_diff + new_diffmin_sum = min(min_sum, new_sum)return min_sum % MOD

反思

  1. 为什么要找到替换为最接近 nums2[i] 的值?

如果我们想让这个差值最小,我们需要让 nums1[i] 尽量接近 nums2[i]。因为:

  • 当两个数接近时,它们的差值 |nums1[i] - nums2[i]| 也会很小。
  • 例如,如果 nums2[i] = 5,而我们有两个候选值 47,显然 47 更接近 5,因此 |4 - 5||7 - 5| 小。
  1. 为什么要使用bisect_left,而不是bisect_right

bisect_left 返回的是数组中第一个大于或等于查找值的位置。bisect_right 返回的是数组中第一个大于查找值的位置。

假设我们有一个排序数组 sorted_nums1 = [1, 2, 4, 4, 7, 10],我们要查找 nums2[i] = 4 在这个数组中的插入点。

  • bisect_left(sorted_nums1, 4) 返回 2,因为 sorted_nums1[2] 是 4,这是第一个大于或等于 4 的位置。
  • bisect_right(sorted_nums1, 4) 返回 4,因为 sorted_nums1[4] 是 7,这是第一个大于 4 的位置。

在这一题目中,我们需要找到最接近 nums2[i] 的值,以尽可能减少绝对差值和。使用 bisect_left 可以帮助我们找到最接近的值,并确保我们不会错过等于 nums2[i] 的值。

  1. 为什么要检查两个位置(pospos-1)?

当我们使用 bisect_left(sorted_nums1, nums2[i]) 时,我们得到的是 nums2[i]sorted_nums1 中的插入位置 pos。这个位置表示在保持数组有序的情况下,nums2[i] 应该插入的位置。

  • pos位置解释:sorted_nums1[pos] 是第一个大于或等于 nums2[i] 的元素。因此,sorted_nums1[pos] 可能是一个接近 nums2[i] 的候选值。
  • pos-1 位置解释:sorted_nums1[pos-1] 是小于 nums2[i] 的最大元素。由于 pos-1 位置的元素也是接近 nums2[i] 的另一个候选值,因此我们也需要检查这个位置。

所以,检查这两个位置的原因为:

  • 全面覆盖可能的候选值
  • 确保找到最优解
  1. pos < npos >0 该如何理解?

当我们使用 bisect_left(sorted_nums1, nums2[i]) 时,得到的 pos 是插入位置,即第一个大于或等于 nums2[i] 的位置。这个位置有可能是数组的末尾,因此我们需要检查 pos < n,确保 pos 在有效范围内。

为什么要检查 pos < n

  • 防止数组越界:如果 pos 恰好等于 n,说明 nums2[i] 大于 sorted_nums1 中的所有元素。在这种情况下,访问 sorted_nums1[pos] 会导致数组越界错误。
  • 确保有效访问:只有在 pos < n 时,我们才能安全地访问 sorted_nums1[pos],因为这时 pos 是一个有效的索引。

类似地,我们还需要检查 pos-1 的位置,以便找到小于 nums2[i] 的最大值。为了确保 pos-1 在有效范围内,我们需要检查 pos > 0

为什么要检查 pos > 0

  • 防止数组越界:如果 pos 恰好等于 0,说明 nums2[i] 小于或等于 sorted_nums1 中的所有元素。在这种情况下,访问 sorted_nums1[pos-1] 会导致数组越界错误。
  • 确保有效访问:只有在 pos > 0 时,我们才能安全地访问 sorted_nums1[pos-1],因为这时 pos-1 是一个有效的索引。

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

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

相关文章

中国 X86 CPU 技术源自何方

注&#xff1a; 原文发布于 2017 年&#xff0c;两篇合二为一。未与作者沟通&#xff0c;侵权&#xff0c;立删。 导语&#xff1a; Intel 对 X86 的授权有着极为严格的限制&#xff0c;那么上海兆芯的 X86 芯片技术到底从何而来&#xff1f;ZX-C 目前的短板在哪里&#xff1f;…

pytorch 46 将ASpanFormer模型导出onnx运行

ASpanFormer是一个2022年8月份发布的算法,其主要步骤与LoFTR模型类似,因此无法导出为onnx模型。根据ASpanFormer论文中的数据与效果图,可以确定AsPanFormer是可以作为一个比SP+SG更为有效的方案,其在标准数据集上的效果优于SP+SG,在速度上远超SP+SG,与LoFTR接近;在预测点…

k8s安装powerjob

k8s安装powerjob k8s安装powerjob 1、mysql mkdir -p ~/powerjob-ymlkubectl create ns powerjobcat > ~/powerjob-yml/powerjob-mysql.yml << EOF apiVersion: v1 kind: ConfigMap metadata:name: powerjob-mysql-confignamespace: powerjob data:my.cnf: |[mysql…

【深度学习入门项目】多层感知器(MLP)实现手写数字识别

多层感知器&#xff08;MLP&#xff09;实现手写数字识别 导入必要的包获得软件包的版本信息 下载并可视化数据查看一个batch的数据查看图片细节信息设置随机种子 定义模型架构Build model_1Build model_2 Train the Network (30 marks)Train model_1Train model_1Visualize th…

理解Go 语言中读写锁 RWMutex

读写锁是计算机程序并发控制的一种针结互斥锁优化的同步机制,也称 “共享-互斥锁” 、多读单写锁等,用于处理大量读、少量写的场景。读操作之间可并发进行,写操作之间是互斥的,读和写又是互斥的。这意味着多个 goroutine 可以同时读数据,但写数据时需要获得一个独占的锁。…

mac电脑显示隐藏文件

方法一&#xff1a; 第一步&#xff1a;打开「终端」应用程序。 第二步&#xff1a;输入如下命令&#xff1a; defaults write com.apple.finder AppleShowAllFiles -boolean true ; killall Finder 第三步&#xff1a;按下「Return」键确认。 现在你将会在 Finder 窗口中…

AI+X活动开放报名!Datawhale来南京了

Datawhale线下 主办方&#xff1a;讯飞开放平台、Datawhale、GDG南京 AIX 主题活动今年将走进 10 个城市&#xff0c;100 所高校&#xff0c;目前已经走进32所高校&#xff0c;以及北京、深圳、上海、杭州、武汉五个城市&#xff0c;南京是第六个城市&#xff0c;时间7月27号。…

IP-Trunk简介

定义 IP-Trunk是将多个链路层协议为HDLC的POS接口捆绑到一起&#xff0c;形成一条逻辑上的数据链路&#xff0c;以提供更高的连接可靠性和更大的带宽&#xff0c;实现流量负载分担。 目的 POS是一种应用在城域网及广域网中的技术&#xff0c;利用SONET/SDH提供的高速传输通道…

html改写vue日志

本人最近学了vue&#xff0c;想着练手的方法就是改写之前在公司开发的小系统前端&#xff0c;将前端的AJAXJSThymeleaf改为axiosvue。 改写html 将<html>中的<head>和<body>结构移除&#xff0c;将css部分移入<style>&#xff0c; 重新定义了全局的&…

视频汇聚,GB28181,rtsp,rtmp,sip,webrtc,视频点播等多元异构视频融合,视频通话,视频会议交互方案

现在视频汇聚&#xff0c;视频融合和视频互动&#xff0c;是视频技术的应用方向&#xff0c;目前客户一般有很多视频的业务系统&#xff0c;如已有GB28181的监控&#xff08;GB现在是国内主流&#xff0c;大量开源接入和商用方案&#xff09;&#xff0c;rtsp设备&#xff0c;音…

x264、x265、libaom 编码对比实验

介绍 x264 是一个开源的高性能 H.264/MPEG-4 AVC 编码器,它以其优秀的压缩比和广泛的适用性而闻名。x265 是一种用于将视频流编码成 H.265/MPEG-H HEVC 压缩格式的免费软件库和应用程序,以其下一代压缩能力和卓越的质量而闻名 。作为 x264 的继任者,x265 支持 HEVC 的 Main、…

科研绘图系列:R语言单细胞聚类气泡图(single cell bubble)

介绍 单细胞的标记基因气泡图是一种用于展示单细胞数据中特定基因表达情况的可视化方法。它通常用于展示细胞亚群中标记基因的表达水平,帮助研究者识别和区分不同的细胞类型。在这种图表中,每个细胞亚群用不同的颜色表示,而基因表达水平则通过气泡的大小来表示,从而直观地…

前端算法入门【栈】

在JavaScript中是不存在栈这个数据结构的&#xff0c;但是我们可以通过数组来模拟栈。 1、基本实现 栈是一种“后进先后”的数据结构&#xff0c;数据在内存中是连续存储的&#xff0c;可以通过数组的 push 来模拟茹栈&#xff0c;pop 来模拟入栈。 // 栈 后进先出 const stac…

Android笔试面试题AI答之Intent(1)

答案仅供参考&#xff0c;来自文心一言 目录 1.请描述一下Intent 和 Intent Filter。IntentIntent Filter总结 2.Intent可以传递哪些类型数据&#xff1f;3.Serializable 和 Parcelable 的区别1. 效率2. 使用方式3. 适用场景4. 其他差异 4.请写出直接拨号、将电话号码传入拨号…

【IEEE出版,会议历史良好、论文录用检索快】第四届计算机科学与区块链国际学术会议 (CCSB 2024,9月6-8)

CCSB 2024会议由深圳大学主办&#xff0c;旨在探讨计算机科学的最新发展如何与区块链技术相结合&#xff0c;以及这一结合如何推动金融、供应链管理、数据安全和其他多个行业的革新&#xff0c; 本次会议将提供一个多学科交流的平台&#xff0c;汇集来自相关领域学者的研究和思…

最优化理论与方法-第十讲-对偶理论的基本性质和割平面法

文章目录 1. 向量化拉格朗日对偶函数2. 对偶问题是凹函数3. 对偶问题转换4. 外逼近法4.1 步骤4.2 注意事项 1. 向量化拉格朗日对偶函数 ( D ) max ⁡ d ( λ , μ ) s t . λ i ≥ 0 , i 1 , ⋯ , m , d ( λ , μ ) min ⁡ x ∈ X { f ( x ) ∑ i 1 m λ i g i ( x ) ∑ …

【AI那些事】YOLO算法在香橙派AIpro上跑起来的初体验

一、本文概述 在之前推出的Yolo算法后&#xff0c;我在windows电脑上使用python语言运行将其跑通了&#xff0c;觉的这个识别算法很是有意思&#xff0c;就一直想着这个算法能不能跑在硬件的开发板上那就太好了。我就开始寻找市面上可行的开发板&#xff0c;一直期盼的事情真的…

【学术研究、研究热点、最新前沿】如何跟踪最新的论文

1.跟踪arxiv 使用https://www.arxivdaily.com/接收每天的推送。 2.跟踪热点文章的引用 使用semantic scholar。 3.跟踪某个学术大佬或者主题 3.1 使用web of science。 3.2 使用文献鸟 4.跟踪某个期刊

迭代学习笔记

一、迭代学习定义和分类 1、直观理解 迭代学习一般应用于重复性的场景。比如控制一个单自由度的小车以特定的速度曲线移动到指定位置&#xff0c;整个时间是10s&#xff0c;控制频率是0.01&#xff0c;那么整个控制序列就会有1000个点。这1000个点在10s内依次发出&#xff0c…

小白快速入门量化交易的自学路径

今年已然过去一半了&#xff0c;年初立的flag都实现了吗&#xff1f; 据我多年来的观察&#xff0c;很多小白萌新开始学习量化&#xff0c;特别是年初的时候立下“宏图大志”&#xff0c;但有相当一部分最终没能"上岸"&#xff0c;从入门到放弃&#xff0c;从然后到没…