m*n的Young氏矩阵定义如下:
- m*n的矩阵
- 每一行,每一列的数据有序
- ∞表示不存在的元素
2 3 5 12
4 8 14 ∞
9 16 ∞ ∞
∞ ∞ ∞ ∞
1. 如何在O(m+n)时间复杂度的条件下实现删除最小元素,并使删除后的矩阵保持为Young氏矩阵?
将矩阵类比成“二叉树”:某一元素下边的元素类比为该元素的左孩子,右边的元素类比为右孩子,则Young氏矩阵可看成一个小根堆。
因此,可参考堆排序中的EXTRACT_MIN算法来实现。
为表达方便,以A[i, j]表示以A[i, j]为左上角边界的矩阵,如A[1, 2]为:
3 5 12
8 14 ∞
16 ∞ ∞
∞ ∞ ∞
首先,需要实现MIN_HEAPIFY。当A[i+1, j]以及A[i, j+1]均为Young氏矩阵时,使以A[i, j]也为Young氏矩阵,伪代码如下:
MIN_HEAPIFY(A, i, j)
min_i = i
min_j = j
if i + 1 <= m && A[i+1][j] < A[i][j]
min_i = i + 1
min_j = j
if j + 1 <= n && A[i][j+1] < A[min_i][min_j]
min_i = i
min_j = j + 1
if min_i != i || min_j != j
exchange A[i][j] <-> A[min_i][min_j]
MIN_HEAPIFY(A, min_i, min_j)
EXTRACT_MIN实现伪代码如下:
EXTRACT_MIN(A)
x <- A[1, 1]
A[1, 1] = A[last_element_i][last_element_j]
A[last_element_i][last_element_j] = ∞
MIN_HEAPIFY(A, 1, 1)
return x
其中last_element_i 与last_element_j满足:与右下角元素距离最小的非∞元素
确定last_element_i与last_element_j的伪代码如下:
GET_LAST_ELEMENT(A, last_element_i, last_element_j)
for s <- m + n - 1 to 2
for i <- m to 1
if 1 <= s - i <= m
j = s - i
if A[i][j] != ∞
last_element_i = i
last_element_j = j
return
2. 在O(m+n)时间内,将一个新元素插入到一个未满的m*n Young氏矩阵中
首先找到与右下角元素距离“最远”的∞元素,将GET_LAST_ELEMENT算法稍作修改即可。其次执行DECREASE_KEY操作,伪代码如下:
DECREASE_KEY(A, i, j, key)
while i >= 1 and j >= 1
max_i = i
max_j = j
A[i][j] = key
if i - 1 >= 1 and A[i-1][j] > key
max_i = i - 1
max_j = j
if j - 1 >= 1 and A[i][j-1] > A[max_i][max_j]
max_i = i
max_j = j - 1
if max_i != i or max_j != j
A[i][j] = A[max_i][max_j]
i = max_i
j = max_j
A[i][j] = key
else
A[i][j] = key
return
3.在O(m+n)时间内,确定一个给定的数是否存在于一个给定m*n的Young氏矩阵
注意到Young氏矩阵右上角元素的特性:该元素大于其左边的同行元素,小于其下边的同列元素。因此,每次用矩阵右上角元素与给定元素比较时,若右上角元素小于给定元素,则可剔除这一行;同理,可剔除这一列。每次比较均可剔除一行或一列,因此,可在O(m+n)的时间内完成任务。
伪代码如下:
FIND_ELEMENT(A, i, j, key)
if i > m or j < 1
return -1
else if A[i][j] == key
return (i, j)
else if A[i][j] < key
return FIND_ELEMENT(A, i + 1, j, key)
else
return FIND_ELEMENT(A, i, j - 1, key)