19-二分-值域二分-有序矩阵中第 K 小的元素

这是二分法的第19篇算法,力扣链接

给你一个 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

这道题很抽象,他告诉我们行和列都是有序的。但是不代表下一列一定大于上一行。

老规矩,直接上暴力法,先把所有数字存起来然后排序。

Go 复制代码
func kthSmallest(matrix [][]int, k int) int {
	nums := make([]int, len(matrix)*len(matrix[0]))
	index := 0
	for _, row := range matrix {
		for _, num := range row {
			nums[index] = num
			index++
		}
	}
	sort.Ints(nums)
	return nums[k-1]
}

那这道题二分法怎么搞呢?

首先明确,无论这个分布怎么诡异,在matrix[0][0]的数一定matrix[len(matrix)-1][len(matrix[0])-1]的数小。我门可以利用这两个值当作边界,往中间找mid,移动左右边界的逻辑可以根据小于等于mid的数的多少。当左右指针相等的时候返回指针就可以了。

这时候还会有一个疑问,当左右指针相等的时候,那个边界的值真的存在吗,这个值不是根据mid左右移动算出来的吗。

其实很简单,求出矩阵元素排序后,把矩阵分成两份,且使得前一份包含k个元素的数值范围左边界值(满足条件的数值可能是个范围,有些值不存在矩阵中,但这个左边界值一定在矩阵中)。可以尝试去推导一下,会发现这个结论是存在的。

上代码:

Go 复制代码
func kthSmallest(matrix [][]int, k int) int {
	l, r := matrix[0][0], matrix[len(matrix)-1][len(matrix[0])-1]
	for l <= r {
		mid := l + (r-l)/2
		if count(mid, matrix) < k {
			l = mid + 1
		} else {
			r = mid - 1
		}
	}
	return l
}

func count(mid int, matrix [][]int) int {
	result, x, y := 0, len(matrix)-1, 0
	for x >= 0 && y < len(matrix[0]) {
		if matrix[x][y] <= mid {
			result += x + 1
			y++
		} else {
			x--
		}
	}
	return result
}

这个count是有点学问的,这个是一列一列的加数字,梯形的方式加。

相关推荐
adam_life1 小时前
OpenJudge_ 简单英文题_04:0/1 Knapsack
算法·动态规划
龙的爹23332 小时前
论文翻译 | The Capacity for Moral Self-Correction in Large Language Models
人工智能·深度学习·算法·机器学习·语言模型·自然语言处理·prompt
鸣弦artha3 小时前
蓝桥杯——杨辉三角
java·算法·蓝桥杯·eclipse
我是聪明的懒大王懒洋洋3 小时前
力扣力扣力:动态规划入门(1)
算法·leetcode·动态规划
丶Darling.3 小时前
Day44 | 动态规划 :状态机DP 买卖股票的最佳时机IV&&买卖股票的最佳时机III
算法·动态规划
TN_stark9324 小时前
多进程/线程并发服务器
服务器·算法·php
汉克老师4 小时前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
smj2302_796826525 小时前
用枚举算法解决LeetCode第3348题最小可整除数位乘积II
python·算法·leetcode
爱吃生蚝的于勒5 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计
秋说6 小时前
【数据结构 | C++】整型关键字的平方探测法散列
数据结构·c++·算法