young氏矩阵的操作及应用

参考:http://wolf5x.cc/blog/algorithm/young-tableau-smallest-kth

杨氏矩阵:一个N*N的矩阵,它的每行每列都单调递增(或者宽松一些,单调不减),即a[i][j]<=a[i+1][j], a[i][j]<=a[i][j+1]。

0. 怎样在杨氏矩阵中查找某个元素X?

1. 输出杨氏矩阵中最小的N个数。

2. 两个升序数组A和B,长度都是N。从两个数组中分别取出一个数,相加得到一个和。求这N*N个和的前N小。

(0) 问题0求解

【方案一】

<二分查找>

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

对于当前子矩阵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+s)/2][(j+t)/2] > x,同样有三块区域。


【方案二】

<类堆查找法>

杨氏矩阵具有明显的堆特征:从矩阵的右上角出发(从左下角出发思路类似),对于元素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),代码如下:

<span style="font-family:Microsoft YaHei;font-size:14px;">bool FindInYongMatrix(int ** array, int M, int N, int s)
{
	if(a!=NUll && M>0 && N>0)
	{
		int row = 0, col = N-1;
		while(row<M && col>=0)
		{
			if(s == array[row][col])
				return true;
			else if(s < array[row][col])
				col--;
			else
				row++;
		}
	}
	return false;
}</span><span style="font-family:Microsoft YaHei;font-size:18px;">
</span>

(1) 问题1求解

【方案一】

<小顶堆法>

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

需要维持bool类型的二维数组。


【方案二】

<N路归并>

N路归并,用一个大小为N的堆,可以O(NlgN)得到解。


(2) 问题2求解

问题二转换成问题一求解。把A[0]+B[k]的结果填入矩阵第一行,A[1]+B[k]的结果填入第二行……就得到一个杨氏矩阵。所以就只考虑第1题。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值