杨氏矩阵:查找x是否在矩阵中,第K大数
参考:http://xudacheng06.blog.163.com/blog/static/4894143320127891610158/
杨氏矩阵(Young Tableau)是一个很奇妙的数据结构,他类似于堆的结构,又类似于BST的结构,对于查找某些元素,它优于堆;对于插入、删除它比BST更方便。
首先介绍一下这个数据结构的定义,Young Tableau有一个m*n的矩阵,让后有一数组 a[k], 其中k<=m*n ,然后把a[k]中的数填入 m*n 的矩阵中,填充规则为(如图1-1):
1. 每一行每一列都严格单调递增(有其他的版本是递减,其原理相同)。
2. 如果将a[k]中的数填完后,矩阵中仍有空间,则填入 ∞。
|
1 |
2 |
3 |
4 |
5 |
6 |
|
|
1 |
3 |
5 |
7 |
8 |
11 |
a |
|
4 |
6 |
9 |
14 |
15 |
19 |
b |
|
10 |
21 |
23 |
33 |
56 |
57 |
c |
|
34 |
37 |
45 |
55 |
∞ |
∞ |
d |
|
∞ |
∞ |
∞ |
∞ |
∞ |
∞ |
e |
图1-1
则现在讨论,这个数据结构的几种操作,而在这些操作中,我们会发现堆排序的影子,并且这些操作具有很好的时间复杂度。
条件:一个已经建好的杨氏矩阵(Young Tableau)
操作:
【1】 在杨氏矩阵中插入元素x ---- Insert(x)
【2】 在杨氏矩阵中删除位于 (x, y) 位置的元素---- Delete(x, y)
【3】 返回x是否在矩阵中----Find(x)
【4】 第k大数
其中1-2操作类似于堆的操作,而3操作类似于BST的操作。下面我就用我
自己的理解把这几个操作加以解释。
【1】 插入操作
本操作的时间复杂度为O( n + m ),其操作类似于堆排序的SIFT-UP算法(具体算法见《算法设计技巧与分析》 M.H,Alsuwaiyel 著)。它的堆的结构在这里表现为某个元素Y[x, y] 下面和右面的两个元素Y[x, y+1] ,Y[x+1, y]均比Y[x, y]要大。于是其插入算法可以描述为,首先把待插入元素以行为主序置于所有有效数字(除了无穷以外的数)最后面,如将x=2,放入 图1-1 的d5的位置,然后执行类似于SIFT-UP的操作,将x与它左边(记为x-l)及上面(记为x-u)的数进行比较,根据比较结果有三种可能的操作:
1:x-u > x 且x-u >= x-l 则将x 与 x-u进行交换
2:x-l > x 且x-l > x-u 则将x 与 x-l进行交换
3: x >= x-l 且 x > x-u 则x 不动,此时已经插入成功
(可以有其他合理的约定)
对例子插入2进行操作如图1-2箭头的操作方向。
|
1 |
2 |
3 |
4 |
5 |
6 |
|
|
1 |
3 |
5 |
7 |
8 |
11 |
a |
|
2 |
6 |
9 |
14 |
15 |
19 |
b |
|
4 |
10 |
21 |
23 |
33 |
57 |
c |
|
34 |
37 |
45 |
55 |
56 |
∞ |
d |
|
∞ |
∞ |
∞ |
∞ |
∞ |
∞ |
e |
图1-2
由上述的操作知其时间复杂度最大为行列之和,即O(m+n)。
【2】 删除操作
操作类似于插入操作,其时间复杂度也为O(m+n)。其操作类似于堆排序的SIFT-DOWN算法。删除算法可以描述为,首先将删除的位置(x, y)的数字删除,然后调整,把杨氏矩阵中的最大值k(可以行为主序进行搜索到最后)填入到被删除位置,然后让此数与其下面的数(k-d)和右面的数进行(k-r)比较,此时比较结果为两种,因为此时元素一定会下移:
1:k-d > k-r 将k-r 和 k进行交换
2:k-d < k-r 将k-d 和 k进行交换
举例 删除图1-1的a3位置的元素5如图1-3
|
1 |
2 |
3 |
4 |
5 |
6 |
|
|
1 |
3 |
7 |
8 |
11 |
19 |
a |
|
4 |
6 |
9 |
14 |
15 |
57 |
b |
|
10 |
21 |
23 |
33 |
56 |
∞ |
c |
|
34 |
37 |
45 |
55 |
∞ |
∞ |
d |
|
∞ |
∞ |
∞ |
∞ |
∞ |
∞ |
e |
图1-3
由操作知,删除算法时间复杂同样最多为行列之和,即O(m + n)。
【3】查找算法
查找算法类似于BST二叉排序树,不过需要在其思想上稍微进行修改,才能满足杨氏矩阵的查找操作,同样利用杨氏矩阵的性质,不过此时应该换一个角度思考问题,因为与BST二叉排序树类比,所以应该从左下角开始看起(如 图1-1d1位置),该元素的上面的元素比本身小和右面的元素比本身大,这样就与BST二叉排序树具有相同的性质。所以在查找时从左下角不断的比较,从而最终确定所查找元素位置。
如查找19,比较顺序如图1-4
|
1 |
2 |
3 |
4 |
5 |
6 |
|
|
1 |
3 |
5 |
7 |
8 |
11 |
a |
|
4 |
6 |
9 |
14 |
15 |
19 |
b |
|
10 |
21 |
23 |
33 |
56 |
57 |
c |
|
34 |
37 |
45 |
55 |
∞ |
∞ |
d |
|
∞ |
∞ |
∞ |
∞ |
∞ |
∞ |
e |
图1-4
此算法的时间复杂度同前两个算法,复杂度也是O(m + n)。
【4】杨氏矩阵第K大数
1)小顶堆法
构建一个小顶堆,首先将a[0][0]加入小顶堆,然后每次从小顶堆中取出最小元素,并加入比该元素大且与之相邻的两个元素(对于a[0][0],则需要加入 a[0][1]和a[1][0]),直到取出第k个元素,需要注意的是,需要采用额外空间记录某个元素是否已经加入到小顶堆以防止重复加入。
2)二分枚举+类堆查找
首先,二分枚举找到一个数x,它比杨氏矩阵中k个数大;然后,利用类堆查找法找到刚好小于x的元素。该算法的时间复杂度为O((m+n)lg(mn)),但不需要额外存储空间。代码如下:
int find_kth_in_YoungTableau(int** a, int m, int n, int k)
{
int low = a[][];
int high = a[m-][n-];
int order = ;
int mid = ;
do {
mid = (low + high) >> ;
order = get_order(a, m, n, mid);
if(order == k)
break;
else if(order > k)
high = mid - ;
else
low = mid + ;
} while(); //二分枚举整,找出正好大于k的一个整数 mid
int row = ;
int col = n - ;
int ret = mid;
while(row <= m- && col >= )
{ //找出比mid小的最大数
if(a[row][col] < mid) {
ret = (a[row][col] > ret) ? a[row][col] : ret;
row++;
} else {
col--;
}
}
return ret;
} //整数k在矩阵中的排名
int get_order(int** a, int m, int n, int k)
{
int row, col, order;
row = ; col = n-; order = ;
while(row <= m- && col >= ) {
if(a[row][col] < k) {
order += col + ;
row++;
}else {
col--;
}
}
return order;
}
方法2举例:要在下列杨氏矩阵中找第k大数,k=6.
| 1 | 3 | 5 |
| 2 | 4 | 8 |
| 6 | 9 | 10 |
首先会对mid进行枚举,重点是对枚举的mid计算其在该矩阵中小于它的有几个数。
下面以mid=7为例,说明order=6.
首先与a[0][2]比较,a[0][2]=5<7,则order = 0+2+1=3, row = 1;
再与a[1][2]比较,a[1][2]=8>7,则col = col-1 = 1;
再与a[1][1]比较,a[1][1]=4<7,则order = 3+1+1 = 5,row = 2;
再与a[2][1]比较,a[2][1]=9>7,则col = col-1 = 0;
在于a[2][0]比较,a[2][0]=6<7,则order = 5+0+1 = 6,row = 3;
row >(m-1)=2,所以退出循环,返回order值等于6,即在该杨氏矩阵中比mid=7小的数一共有6个。
PS:发现如果数组中有相同的值的话,可能无法通过枚举找到恰好比杨氏矩阵中k个数大的数。所以这种方法有其局限性。
杨氏矩阵:查找x是否在矩阵中,第K大数的更多相关文章
- 寻找数组中第K大数
1.寻找数组中的第二大数 using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...
- 二叉堆的应用——查找长度为N数组中第M大数
看到这个题目首先想到是排序,那么时间复杂度自然就是O(NlgN).那么使用二叉堆如何解决呢? 对于下面一个数组,共有12个元素,我们的目标就是找出第5大元素——12 首先建立一个具有M个元素的最小堆, ...
- 查找数组中第k大的数
问题: 查找出一给定数组中第k大的数.例如[3,2,7,1,8,9,6,5,4],第1大的数是9,第2大的数是8-- 思考:1. 直接从大到小排序,排好序后,第k大的数就是arr[k-1]. 2. ...
- 杨氏矩阵查找元素位置Java实现
杨氏矩阵是一个二维矩阵,特点是每一行的右边的元素比左边的大,每一列下面的元素比上面的大: 比如 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 假设要查找的变量为target ...
- [LeetCode] Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素
Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...
- [LeetCode] 378. Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素
Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...
- LeetCode 378. 有序矩阵中第K小的元素(Kth Smallest Element in a Sorted Matrix) 13
378. 有序矩阵中第K小的元素 378. Kth Smallest Element in a Sorted Matrix 题目描述 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩 ...
- leetcode.矩阵.378有序矩阵中第K小的元素-Java
1. 具体题目 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素.请注意,它是排序后的第k小元素,而不是第k个元素. 示例: matrix = [ [ 1, 5, ...
- 有序矩阵中第k小元素
有序矩阵中第k小元素 题目: 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素. 请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素. 看到有序就会想 ...
随机推荐
- XTREE随笔
1.XTREE简介: XTREE是一个基于AJAX实现的树形菜单.它的原理就是每次都只加载当前结点下的所有结点,而对开发人员来说,就是只需要按一定的格式,生成一段XML代码.XTREE可以自己定制每个 ...
- zabbix3配置短信报警
需求:在zabbix服务器配置短信报警,当服务出现故障达到预警级别是通过发送短信的形式告诉运维人员,以便及时处理. 一.zabbix服务器端配置短信脚本 我的短信脚本放置位置为 /etc/zabbix ...
- (转载)详解网络传输中的三张表,MAC地址表、ARP缓存表以及路由表
郑重声明:原文转载于http://dengqi.blog.51cto.com/5685776/1223132 向好文章致敬!!! 一:MAC地址表详解 说到MAC地址表,就不得不说一下交换机的工作原理 ...
- 浅谈JavaScript、ES5、ES6
// http://es6.ruanyifeng.com/#docs/intro (ES6 文档) 什么是JavaScript JavaScript一种动态类型.弱类型.基于原型的客户端脚本语言,用来 ...
- 《锋利的jQuery(第2版)》笔记-第2章-jQuery选择器
选择器是jQuery的根基,在jQuery中,对事件处理.遍历DOM和Ajax操作都依赖于选择器.熟练使用选择器,不仅可以简化代码,而且可以达到事半功倍的效果. 2.1 jQuery选择器是什么 1. ...
- 2.2、Hibernate用注解方式实现一对多、多对多关系
一.一对多关系 1.在上一篇日志中用.xml配置文件项目基础上,再往lib目录先添加一个包-hibernate-jpa-2.0-api-1.0.0.Final.jar 2.新建一个com.st.bea ...
- JAVA过滤器
对于get请求和post请求全局过滤: 自己创建一个类,实现HttpServletRequestWrapper接口 package com.dh.deno; import java.io.Buffer ...
- 如何在ARM中创建Express Route
很早之前就想试试Azure的express route,但是一直没有找到合适的机会,正好有个客户需要上express route,所以最近先自己研究研究,防止在做poc的时候耗费更多时间,本次场景我们 ...
- composer
composer 是PHP框架的包安装工具,类似于bower ,npm.bundler. 是命令行工具,没有图形界面. 系统要求 运行 Composer 需要 PHP + 以上版本.一些敏感的 PHP ...
- 变量声明---let,const,解构
let在很多方面与var是相似的,但是可以帮助大家避免在JavaScript里常见一些问题. const是对let的一个增强,它能阻止对一个变量再次赋值. 块作用域 当用let声明一个变量,它使用的是 ...