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氏矩阵,伪代码如下:
1 MIN_HEAPIFY(A, i, j) 2 min_i = i 3 min_j = j 4 if i + 1 <= m && A[i+1][j] < A[i][j] 5 min_i = i + 1 6 min_j = j 7 if j + 1 <= n && A[i][j+1] < A[min_i][min_j] 8 min_i = i 9 min_j = j + 1 10 if min_i != i || min_j != j 11 exchange A[i][j] <-> A[min_i][min_j] 12 MIN_HEAPIFY(A, min_i, min_j)
EXTRACT_MIN实现伪代码如下:
1 EXTRACT_MIN(A) 2 x <- A[1, 1] 3 A[1, 1] = A[last_element_i][last_element_j] 4 A[last_element_i][last_element_j] = ∞ 5 MIN_HEAPIFY(A, 1, 1) 6 return x
其中last_element_i 与last_element_j满足:与右下角元素距离最小的非∞元素
确定last_element_i与last_element_j的伪代码如下:
1 GET_LAST_ELEMENT(A, last_element_i, last_element_j) 2 for s <- m + n - 1 to 2 3 for i <- m to 1 4 if 1 <= s - i <= m 5 j = s - i 6 if A[i][j] != ∞ 7 last_element_i = i 8 last_element_j = j 9 return
2. 在O(m+n)时间内,将一个新元素插入到一个未满的m*n Young氏矩阵中
首先找到与右下角元素距离“最远”的∞元素,将GET_LAST_ELEMENT算法稍作修改即可。其次执行DECREASE_KEY操作,伪代码如下:
1 DECREASE_KEY(A, i, j, key) 2 while i >= 1 and j >= 1 3 max_i = i 4 max_j = j 5 A[i][j] = key 6 if i - 1 >= 1 and A[i-1][j] > key 7 max_i = i - 1 8 max_j = j 9 if j - 1 >= 1 and A[i][j-1] > A[max_i][max_j] 10 max_i = i 11 max_j = j - 1 12 if max_i != i or max_j != j 13 A[i][j] = A[max_i][max_j] 14 i = max_i 15 j = max_j 16 A[i][j] = key 17 else 18 A[i][j] = key 19 return
3.在O(m+n)时间内,确定一个给定的数是否存在于一个给定m*n的Young氏矩阵
注意到Young氏矩阵右上角元素的特性:该元素大于其左边的同行元素,小于其下边的同列元素。因此,每次用矩阵右上角元素与给定元素比较时,若右上角元素小于给定元素,则可剔除这一行;同理,可剔除这一列。每次比较均可剔除一行或一列,因此,可在O(m+n)的时间内完成任务。
伪代码如下:
1 FIND_ELEMENT(A, i, j, key) 2 if i > m or j < 1 3 return -1 4 else if A[i][j] == key 5 return (i, j) 6 else if A[i][j] < key 7 return FIND_ELEMENT(A, i + 1, j, key) 8 else 9 return FIND_ELEMENT(A, i, j - 1, key)