leetcode分类刷题:二分查找(Binary Search)(四、基于值域的数组/矩阵类型)

基于值域的二分法与基于定义域的题型不同,它的目标是从一“特殊排序序列”中确定“第k个元素值”,而不像基于定义域的题型是从排序序列中找小于等于特定target值的第一个索引;同时,针对“特殊排序序列”,往往需要嵌套使用双指针法进行操作,进一步增加了对应题型的难度。

378. 有序矩阵中第 K 小的元素

from typing import List
'''
378. 有序矩阵中第 K 小的元素
题目描述:给你一个n x n矩阵matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
你必须找到一个内存复杂度优于O(n2) 的解决方案。
示例 1:输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8输出:13解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13
题眼:每行和每列元素均按升序排序 有序矩阵
思路:(有点难度,看了官方解答才明白)值域的二分法:确定左右两侧边界为matrix[0][0]=leftVal和matrix[n-1][n-1]=rightVal,二分后统计小于等于midVal的数量,讨论与k的大小关系,保证第k小的数始终位于leftVal~rightVal之间(即保证在左闭右闭区间内[leftVal,rightVal]),当leftVal==rightVal时,第k小的数即被找出这道题就是在“二分式”缩小目标值的值域区间范围!也可以看到,这个题的target值不像之前一样是给定然后确定存在位置了,是要确定其值。
'''class Solution:def kthSmallest(self, matrix: List[List[int]], k: int) -> int:n = len(matrix)leftVal, rightVal = matrix[0][0], matrix[n-1][n-1]# 确定target所在的区间[leftVal, rightVal],对矩阵中小于等于中间值midVal的元素数目进行统计# 关键思路:如果数目小于k,说明target>midVal;即左边界leftVal = midVal + 1# 如果数目等于k,说明target<=midVal;即右边界rightVal = midVal# 如果数目大于k,说明target<=midVal;即右边界rightVal = midValwhile leftVal < rightVal:midVal = leftVal + (rightVal-leftVal) // 2count = self.checkSmallEqualMid(matrix, midVal)  # 表示小于等于mid的数量if count < k:  # 第k小的数在midVal的右侧,且不包含midValleftVal = midVal + 1elif count >= k:  # 第k小的数在midVal的左侧,可能包含midValrightVal = midValreturn leftValdef checkSmallEqualMid(self, matrix: List[List[int]], midVal: int) -> int:n = len(matrix)# 双指针:根据矩阵的特殊性质,从左下角开始统计i, j = n - 1, 0count = 0while i >= 0 and j <= n - 1:  # 索引必须在边界之内if matrix[i][j] <= midVal:count += i + 1  # 对应行及行以上全部统计j += 1  # 并更新列数else:i -= 1  # 更新行数return countif __name__ == '__main__':obj = Solution()while True:try:in_line = input().strip().split('=')matrix = []for row in in_line[1].strip()[1: -4].split(']')[:-1]:matrix.append([int(n) for n in row.split('[')[1].split(',')])k = int(in_line[2])# print(matrix, k)print(obj.kthSmallest(matrix, k))except EOFError:break

373. 查找和最小的 K 对数字

from typing import List
'''
373. 查找和最小的 K 对数字
题目描述:给定两个以 升序排列 的整数数组 nums1 和 nums2,以及一个整数 k。
定义一对值(u,v),其中第一个元素来自nums1,第二个元素来自 nums2。
请找到和最小的 k个数对(u1,v1), (u2,v2) ... (uk,vk)。
示例 1:输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3输出: [1,2],[1,4],[1,6]解释: 返回序列中的前 3 对数:[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
题眼:组合num1为行索引,num2为列索引,可实现 每行和每列元素均按升序排序 有序矩阵,类似于”378. 有序矩阵中第 K 小的元素“
思路:值域二分法,注意返回的不是第k小,而是前k小(看了官网解析也觉得很难,这个题应该更适合其它算法来解)
'''class Solution:def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:result = []m, n = len(nums1), len(nums2)# 第一步,值域二分法找到第k小的数,确定pairSum所在的区间[leftVal, rightVal],对矩阵中小于等于中间值midVal的元素数目进行统计leftVal, rightVal = nums1[0]+nums2[0], nums1[m-1]+nums2[n-1]while leftVal < rightVal:midVal = (leftVal + rightVal) // 2count = self.checkSmallEqualMid(nums1, nums2, midVal)  # 表示小于等于中间值midVal的数量if count < k:  # 第k小的数在midVal的右侧,且不包含midValleftVal = midVal + 1elif count >= k:  # 第k小的数在midVal的左侧,可能包含midValrightVal = midValpairSum = leftVal# 第二步,将小于pairSum的数对升序添加到result中# 分为两步添加是为了避免等于pairSum的数对和太多,导致所有小于的没有被添加到result中# 双指针:根据两个数组的特殊性质,i取nums1的最小值位置,j取nums2的最大值位置(以nums1为基准进行)i, j = 0, len(nums2) - 1while i < len(nums1) and j >= 0:  # 索引必须在边界之内if nums1[i] + nums2[j] < pairSum:for t in range(j + 1):result.append([nums1[i], nums2[t]])# if len(result) == k:  # 这里可以不用判断,小于pairSum的数对一定小于k个#     return resulti += 1elif nums1[i] + nums2[j] >= pairSum:j -= 1# 以下过程是上述双指针法 的等价形式# i2 = n - 1# for i1 in range(m):#     while i2 >= 0 and nums1[i1] + nums2[i2] >= pairSum:  # 用while直到小于pairSum的数对出现#         i2 -= 1#     for j in range(i2 + 1):  # 将该索引之前的nums2构成的数对,包括本身,全部添加到result#         result.append([nums1[i1], nums2[j]])#         if len(result) == k:#             return result# 第三步,将等于pairSum的数对升序添加到result中# 双指针:根据两个数组的特殊性质,i取nums1的最小值位置,j取nums2的最大值位置(以nums1为基准进行)i, j = 0, len(nums2) - 1while i < len(nums1) and j >= 0:  # 索引必须在边界之内if nums1[i] + nums2[j] < pairSum:i += 1elif nums1[i] + nums2[j] > pairSum:j -= 1else:t = j  # 添加nums2元素时考虑重复情况,同时j的位置要被记录而不能被更新while t >= 0 and nums1[i] + nums2[t] == pairSum:result.append([nums1[i], nums2[t]])if len(result) == k:return resultt -= 1i += 1# 以下过程是上述双指针法 的等价形式# i2 = n - 1# for i1 in range(m):#     while i2 >= 0 and nums1[i1] + nums2[i2] > pairSum:  # 用while过滤掉大于pairSum的数对#         i2 -= 1#     j = i2#     while j >= 0 and nums1[j] + nums2[i2] == pairSum:  # 用while是为了将nums2中的全部重复元素添加上#         result.append([nums1[i1], nums2[j]])#         if len(result) == k:#             return result#         j -= 1return resultdef checkSmallEqualMid(self, nums1: List[int], nums2: List[int], midVal: int) -> int:# 双指针:根据两个数组的特殊性质,i取nums1的最小值位置,j取nums2的最大值位置i, j = 0, len(nums2) - 1count = 0while i < len(nums1) and j >= 0:  # 索引必须在边界之内if nums1[i] + nums2[j] <= midVal:count += j + 1  # 对应nums2位置元素及之前的全部统计i += 1else:j -= 1return countif __name__ == '__main__':obj = Solution()while True:try:in_line = input().strip().split('=')nums1 = [int(n) for n in in_line[1].strip().split('[')[1].split(']')[0].split(',')]nums2 = [int(n) for n in in_line[2].strip().split('[')[1].split(']')[0].split(',')]k = int(in_line[3])# print(nums1, nums2, k)print(obj.kSmallestPairs(nums1, nums2, k))except EOFError:break

719. 找出第 K 小的数对距离

from typing import List
'''
719. 找出第 K 小的数对距离
题目描述:数对 (a,b) 由整数 a 和 b 组成,其数对距离定义为 a 和 b 的绝对差值。
给你一个整数数组 nums 和一个整数 k ,数对由 nums[i] 和 nums[j] 组成且满足 0 <= i < j < nums.length 。
返回 所有数对距离中 第 k 小的数对距离。
示例 1:输入:nums = [1,3,1], k = 1输出:0解释:数对和对应的距离如下:(1,3) -> 2(1,1) -> 0(3,1) -> 2距离第 1 小的数对是 (1,1) ,距离为 0 。
题眼:第k小,必然是要经过排序的
思路:排序+值域二分法(完全想不到和“378. 有序矩阵中第 K 小的元素”、“373. 查找和最小的 K 对数字”是类似题型:
注意最小取值为0,最大为末端减去首端)+双指针
'''class Solution:def smallestDistancePair(self, nums: List[int], k: int) -> int:# 第一步,将数组升序排列nums.sort()n = len(nums) - 1# 第二步,值域二分法:确保第k小的 数对距离,确定所在的区间[leftVal, rightVal]leftVal, rightVal = 0, nums[n] - nums[0]  # 注意最小取值为0,最大为末端减去首端while leftVal < rightVal:midVal = (leftVal + rightVal) // 2count = self.countSmallEqual(nums, midVal)  # 表示小于等于中间值midVal的数量if count < k:  # 第k个数对距离 一定大于midValleftVal = midVal + 1elif count >= k:  # 第k个数对距离 可能小于或等于midValrightVal = midValreturn leftValdef countSmallEqual(self, nums: List[int], midVal: int) -> int:# 双指针统计小于等于midVal的数对距离个数count = 0i, j = 0, 1  # i,j指向数组第一、第二位置while i < len(nums) - 1:  # i<j所以i不能取到最后一个索引if j < len(nums) and nums[j] - nums[i] <= midVal:j += 1elif j < len(nums) and nums[j] - nums[i] > midVal:  # 满足统计条件:索引全部有效时,第一次出现超过midVal的距离时,# 把前面满足小于等于midVal的距离对全部添加上count += (j - i - 1)i += 1elif j == len(nums):  # 当j已经遍历到头时,与上面满足统计条件的操作一致,可以合并count += (j - i - 1)i += 1return countif __name__ == "__main__":obj = Solution()while True:try:in_line = input().strip().split('=')nums = [int(n) for n in in_line[1].split('[')[1].split(']')[0].split(',')]k = int(in_line[2])print(obj.smallestDistancePair(nums, k))except EOFError:break

个人总结体会

通过刷上述几道题目,除了掌握了基于值域的二分法步骤和模板,也同时掌握了对于行列递增的矩阵、两个递增的数组求和、单个递增的数组求元素对距离 这种“特殊序列”里用双指针法确定小于等于某一数值的元素或组合个数。

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

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

相关文章

Linux stat 命令及示例

介绍 该stat命令打印有关文件和文件系统的详细信息。该工具提供有关所有者是谁、修改日期、访问权限、大小、类型等信息。 该实用程序对于故障排除、在更改文件之前获取有关文件的信息以及例行文件和系统管理任务至关重要。 本文stat通过实际示例解释了有关 Linux 命令的所有…

文旅景区vr体验馆游乐场vr项目是什么

我们知道现在很多的景区或者游玩的地方&#xff0c;以及学校、科技馆、科普馆、商场或公园或街镇&#xff0c;都会建一些关于游玩以及科普学习的项目。从而增加学习氛围或者带动人流量等等。这样的形式&#xff0c;还是有很好的效果呈现。 普乐蛙VR体验馆案例 下面是普乐蛙做的…

单片机学习-蜂鸣器如何发出声音

硬件电路 软件编写 ①发出声音 #include "reg52.h" typedef unsigned int u16; // 重新定义 类型 typedef unsigned char u8; // 重新定义 类型sbit BEEP P2^5; //定义 P2第五个管教 为BEEP // 延时函数 void delay_time(u16 times) {while(times--); } vo…

UI位置与布局

UI位置与布局 引言 发现UGUI的RectTransform定位还是很复杂的&#xff0c;感觉有必要详细了解一下 RectTransform 继承自Transform。他的local position由其他几个变量控制。建议不要直接设置position 目的是为了实现UI自动布局。这套方法将绝对定位&#xff0c;相对定位&a…

<MySon car=“宝马“ :money=“money“></MySon>有没有冒号

为什么car"宝马"没有&#xff1a; 但是 :money"money"就有&#xff1a; <script setup> import {ref} from vue import MySon from /components/MySon.vueconst money ref(100) </script><template><h3>father</h3><My…

CH02_重构的原则(什么是重构、为什么重构、何时重构)

什么是重构 重构&#xff08;名词&#xff09;&#xff1a;对软件内部结构的一种调整&#xff0c;目的是在不改变软件可观察行为的前提下&#xff0c;提高其可理解性&#xff0c;降低其修改成本。 重构&#xff08;动词&#xff09;&#xff1a;使用一系列重构手法&#xff0…

VScode的PHP远程调试模式Xdebug

目录 第一步、安装VScode中相应插件 remote-ssh的原理 ssh插件&#xff1a; PHP相关插件&#xff1a; 第二步、安装对应PHP版本的xdebug 查看PHP具体配置信息的phpinfo页面 1、首先&#xff0c;打开php编辑器&#xff0c;新建一个php文件&#xff0c;例如&#xff1a;inde…

iOS App签名与重签名:从开发者证书到重新安装运行

前文回顾&#xff1a; iOS脱壳技术&#xff08;二&#xff09;&#xff1a;深入探讨dumpdecrypted工具的高级使用方法 iOS逆向&#xff1a;越狱及相关概念的介绍 在本文中&#xff0c;我们将详细介绍iOS应用的签名过程&#xff0c;包括开发者证书的种类、证书与App ID、Provisi…

【ffmpeg】基于需要使用videocapture的opencv编译配置(C++)

目录 配置简介ffmpeg源码编译方法记录gstreamer命令行安装方法opencv的编译项记录 配置简介 opencv使用videocapture读取视频流时&#xff0c;需要借助底层的ffmpeg库。如果不能正确编译&#xff0c;会报错&#xff0c;现记录正确编译配置方法。 ffmpeg源码编译方法记录 ope…

一种IDEA疑难杂症的解决办法

解决办法 重启IDEA 针对于IDEA各种解析&#xff0c;运行时问题&#xff0c;但是无法通过搜索引擎得到答案的问题请试试此方法。 删除根目录下[.idea]文件夹后重启 此文件夹为idea首次导入项目时根据项目情况自动生成的配置文件。方便idea下次更快的解析项目。但是某些情况&a…

Pimpl模式

写在前面 Pimpl(Pointer to implementation&#xff0c;又称作“编译防火墙”) 是一种减少代码依赖和编译时间的C编程技巧&#xff0c;其基本思想是将一个外部可见类(visible class)的实现细节&#xff08;一般是所有私有的非虚成员&#xff09;放在一个单独的实现类(implemen…

用MFC打开外部程序

在MFC&#xff08;Microsoft Foundation Classes&#xff09;中&#xff0c;你可以使用ShellExecute函数来打开Notepad并加载指定的文件。ShellExecute函数是Windows API的一部分&#xff0c;它可以执行与操作系统相关的操作&#xff0c;例如打开文件、运行程序等。 以下是在M…

算法修炼Day60|● 84.柱状图中最大的矩形

LeetCode:84.柱状图中最大的矩形 84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 1.思路 双指针思路&#xff0c;以当前数组为中心&#xff0c;借助两个数组存放当前数柱左右两侧小于当前数柱高度的索引&#xff0c;进行h*w的计算。注意首尾节点的左侧索引…

牛客练习赛 114

C.Kevin的七彩旗 思路&#xff1a;贪心和dp均可以解决。 贪心&#xff1a;我们可以发现&#xff0c;最终想要获得合法的序列&#xff0c;我们必须是通过把几段连续的序列拼凑起来&#xff0c;但序列之间可能有重合&#xff0c;因此我们就转化为了&#xff0c;记录每一段最大的…

elementuiplus设置scroll-to-error之后 提示被遮挡的解决方案

项目场景&#xff1a; 普通的头部固定&#xff0c;中间滑动的布局&#xff0c;中间内容有表单&#xff0c;提交校验不通过时滚动到第一个错误项 问题描述 elementuiplus的scroll-to-error设置之后是局部滚动 当头部内容层级高于中间表单的时候&#xff0c;错误会被遮挡。 ---…

【HarmonyOS】实现将pcm音频文件进行编码并写入文件(API6 Java)

【关键字】 音频编码、管道模式、createEncoder 【写在前面】 在使用API6开发HarmonyOS应用时&#xff0c;如何将pcm源文件进行编码并写入文件&#xff0c;最后生成aac文件&#xff0c;本文直接附上主要代码开发步骤供大家参考。 【主要功能代码】 import ohos.media.codec.…

【C++】4、Preprocessor 预处理:条件编译、源文件包含、宏替换、重定义行号、错误信息、编译器预留指令

文章目录 一、概述二、格式2.1 条件编译2.2 源文件包含2.3 宏替换2.3.1 语法2.3.2 C标准内置的预定义宏 2.4 重定义行号和文件名2.5 错误信息2.6 编译器预留指令 三、应用场景 C的 Build 可分为4个步骤&#xff1a;预处理、编译、汇编、链接。 预处理就是本文要详细说的宏替换…

基于Red Hat Enterprise Linux 7操作系统的PostgresSql15的备份恢复(实践笔记)

零、前言 本文是基于阿里云ECS服务器进行的实践操作&#xff0c;操作系统版本&#xff1a;Red Hat Enterprise Linux 7 PG数据库版本&#xff1a;PostgresSql 15 PG安装方式&#xff1a;yum 由于本人新接触pg数据&#xff0c;本次也是出于好奇&#xff0c;就对pg数据库的pg_du…

C#,《小白学程序》第五课:队列(Queue)

1 文本格式 /// <summary> /// 《小白学程序》第五课&#xff1a;队列&#xff08;Queue&#xff09; /// 日常生活中常见的排队&#xff0c;软件怎么体现呢&#xff1f; /// 排队的基本原则是&#xff1a;先到先得&#xff0c;先到先吃&#xff0c;先进先出 /// </su…

iOS开发Swift-枚举

枚举&#xff1a;一组相关的值定义了一个共同的类型&#xff0c;使你可以在代码中以类型安全的方式来使用这些值。 1.枚举语法 //枚举成员不会被赋予默认的整型值。成员本身就是完备的值&#xff0c;类型为CompassPoint。 enum CompassPoint {case northcase southcase eastcas…