您的位置:首页 > 其它

leetcode - 240.Search a 2D Matrix II

2017-03-11 20:14 357 查看
算法系列 — leetcode

题目描述:

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.

If there is an element equal to the value, return True; otherwise return False.

最最理想的解法,复杂度为O(m+n),不过我并没有想到

直接从矩阵的右上角开始搜索, 用mark表示搜索位的所有信息

如果target = mark,找到返回True

如果target > mark,则向下搜索

如果target < mark,则向左搜索

直至出界,则说明没有这个元素,返回False

矩阵每行都是从左至右升序,每列都是从上到下升序,如果target在矩阵中某个位置

初始mark在整个矩阵的右上角,所以target在其左下方

每次搜索只移动一步,移动的规则也总是能够保证移动之后target仍然是在mark左下方

那么在经过有限步移动之后target必然和mark重合

mark向下最多移动m步,向左最多移动n步,因而时间复杂度为O(m+n)

def searchMatrix(matrix, target):
i = 0
j = len(matrix[0])
while i < len(matrix) and j >= 0:
if matrix[i][j] == target:
return True

if matrix[i][j] < target:
i++
else :
j--

return False


无论怎样看,这个解法都非常精简优雅,不过,我最初的目的是要练习分治算法,似乎这个解法里面并没有分治的思想

暴力枚举配合二分法

由于每行和每列都是有序的,很容易就能想到对每行(或每列)进行二分搜索

不难分析算法时间复杂度为O(N*logM)或者O(M*logN)

def searchMatrix(matrix, target):
cols = len(matrix[0])
for x in range(0, len(matrix)):
if matrix[x][0] <= target && matrix[x][cols-1] >= target && binarySearch(matrix[x], target):
return True
return False

def binarySearch(li, target):
start = 0
end = len(li) - 1
while(end > start):
mid = int((start + end) / 2)
if target == li[mid]:
return True
elif target > li[mid]:
start = mid + 1
else :
end = mid - 1
return li[end] == target


这个算法看起来就既没有技术含量也没有上面的那个算法优雅了,不过至少不是O(M*N)

分治思想配合二分法

由于给定的矩阵比较特殊,每行每列均是升序的,因而可以缩小矩阵规模以分治

最简单的就是将矩阵二等分或者四等分,但是矩阵各个部分都是不同的,因此很难通过减少重复动作来降低复杂度

只能通过剪枝来减小递归系数,而等分矩阵很难进行剪枝

从剪枝这个角度入手,自然是想将矩阵中不可能存在target的部分给抛弃掉

假设matrix[i][j] < target,那么它左上方的子矩阵便可全部抛弃

如果还有matrix[i+1][j+1] > target, 那么此元素右下方的子矩阵也可全部抛弃

因而只需要对matrix[i][j]左下方和右上方的两个子矩阵再进行查找,然后将两个结果归并起来即可

注意到对角线(i=j,在矩阵中不是很严格)上的元素也是升序的,因而可以通过二分查找来确定这个划分矩阵的关键元素

此处的复杂度分析涉及到两个变量,且关键元素位置不是确定的,因而比较困难,我再研究研究

不过估算应该是介于O(M*logN)和O(M+N)之间的; 边界条件不再累述,代码之中会有所反映

def _searchMatrix(matrix, target):
return searchMatrix(matrix, target, 0, 0, len(matrix)-1, len(matrix[0])-1)

def searchMatrix(matrix, target, si, sj, ei, ej):
if si > ei or sj > ej or target < matrix[si][sj]:
return False
if si == ei:
for j in range(sj, ej+1):
if target == matrix[si][j]:
return True
return False
elif sj == ej:
for i in range(si, ei+1):
if target == matrix[i][sj]:
return True
return False

start = 0
end = min((ei - si), (ej - sj))
while end > start + 1:
mid = int((start + end) / 2)
if target > matrix[si + mid][sj + mid]:
start = mid
elif target < matrix[si + mid][sj + mid]:
end = mid
else :
return True

if target > matrix[si+start+1][sj+start+1]:
start += 1
elif target == matrix[si+start+1][sj+start+1] \
or target == matrix[si+start][sj+start]:
return True
return searchMatrix(matrix, target, si+start+1, sj, ei, sj+start) or searchMatrix(matrix, target, si, sj+start+1, si+start, ej)


这个算法虽然没有第一个算法那么简洁并且高效,比第二个算法看上去也复杂了一点,

在这个问题上也没有收获到很大的成果,但是在这个过程中对分治的思想训练很有帮助

作为刚上路的菜鸟,慢慢学吧,总会好的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: