博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
young氏矩阵
阅读量:4154 次
发布时间:2019-05-25

本文共 2174 字,大约阅读时间需要 7 分钟。

http://www.jobcoding.com/array/matrix/young-tableau-problem/

如果一个矩阵每一行每一列都严格单调递增,我们称该矩阵为杨氏矩阵(Young Tableau)。对于杨氏矩阵(a[m][ n]),通常会涉及两个问题:(1) 怎样在杨氏矩阵中查找某个元素X?(2) 怎样在杨氏矩阵找第k大的数?

2. 解决方案

杨氏矩阵是一种非常巧妙的数据结构,它既可以用来当堆,又可以用来当做平衡树。

(1) 问题1求解

【方案一】

<二分查找>

对于杨氏矩阵,由于每行每列均是有序的,则可以于矩阵采用二分查找。具体方法是:

对于当前子矩阵a[i][j]~a[s][t],中间元素为a[(i+s)/2][(j+t)/2],如果a[(i+s)/2][(j+t)/2]==x,则找出该元素;如果a[(i+s)/2][(j+t)/2] > x,则在子矩阵a[i][j]~a[(i+s)/2][(j+t)/2]中查找;如果a[(i+s)/2][(j+t)/2] < x,则在三个子矩阵:a[i][(j+t)/2]~ a[(i+s)/2][t],a[(i+s)/2][(j+t)/2]~ a[s][t]和a[(i+s)/2][j]~ a[s][ (j+t)/2]中查找。该算法的递归式为f(mn)=3f(mn/4)+O(1),根据主定理知,时间复杂度为:O((mn)^(log4(3)))。

【方案二】

<类堆查找法>

杨氏矩阵具有明显的堆特征:从矩阵的右上角出发(从左下角出发思路类似),对于元素a[i][j],如果a[i][j]==x,则找到元素x,直接返回;如果a[i][j] > x,则向下移动,即继续比较a[i+1][j]与x;如果a[i][j]<x,则向左移动,即继续比较a[i][j-1]与x。该算法的时间复杂度是O(m+n),代码如下:

bool find_in_YoungTableau(int** a, int m, int n, int x) {  assert(a != NULL && m > 0 && n > 0);  int row, col;  row = 0;  col = n-1;  while(row <= m-1 && col >= 0) {    if(a[row][col] == x)      return true;    else if(a[row][col] > x)      col--;    else      row++;  }  return false;}

(2) 问题2求解

【方案一】

<小顶堆法>

首先将a[0][0]加入小顶堆,然后每次从小顶堆中取出最小元素,并加入比该元素大且与之相邻的两个元素(对于a[0][0],则需要加入a[0][1]和a[1][0]),直到取出第k个元素,需要注意的是,需要采用额外空间记录某个元素是否已经加入到小顶堆以防止重复加入。

【方案二】

<二分枚举+类堆查找>

首先,二分枚举找到一个数x,它比杨氏矩阵中k个数大;然后,利用类堆查找法找到刚好小于x的元素。该算法的时间复杂度为O((m+n)lg(mn)),但不需要额外存储空间。代码如下:

int find_kth_in_YoungTableau(int** a, int m, int n, int k) {  int low = a[0][0];  int high = a[m-1][n-1];  int order = 0;  int mid = 0;  do {    mid = (low + high) >> 1;    order = get_order(a, m, n, mid);    if(order == k)      break;    else if(order > k)      high = mid - 1;    else      low = mid + 1;  } while(1); //二分枚举整,找出正好大于k的一个整数 mid    int row = 0;  int col = n - 1;  int ret = mid;  while(row <= m-1 && col >= 0) { //找出比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 = 0;  col = n-1;  order = 0;  while(row <= m-1 && col >= 0) {    if(a[row][col] < k) {      order += col + 1;      row++;    } else {      col--;    }  }  return order;}

转载地址:http://bseti.baihongyu.com/

你可能感兴趣的文章
配置文件的重要性------轻化操作
查看>>
又是缓存惹的祸!!!
查看>>
为什么要实现程序指令和程序数据的分离?
查看>>
我对C++ string和length方法的一个长期误解------从protobuf序列化说起(没处理好会引起数据丢失、反序列化失败哦!)
查看>>
一起来看看protobuf中容易引起bug的一个细节
查看>>
无protobuf协议情况下的反序列化------貌似无解, 其实有解!
查看>>
make -n(仅列出命令, 但不会执行)用于调试makefile
查看>>
makefile中“-“符号的使用
查看>>
go语言如何从终端逐行读取数据?------用bufio包
查看>>
go的值类型和引用类型------重要的概念
查看>>
求二叉树中结点的最大值(所有结点的值都是正整数)
查看>>
用go的flag包来解析命令行参数
查看>>
来玩下go的http get
查看>>
队列和栈的本质区别
查看>>
matlab中inline的用法
查看>>
如何用matlab求函数的最值?
查看>>
Git从入门到放弃
查看>>
java8采用stream对集合的常用操作
查看>>
EasySwift/YXJOnePixelLine 极其方便的画出真正的一个像素的线
查看>>
Ubuntu系统上安装Nginx服务器的简单方法
查看>>