剑指offer JZ01 二维数组中的查找 Python 多解

一.题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

二.解题思路

要注意数组的有序信息

1.暴力穷举:O(M*N)

2.单折半:O(M*logN):迭代每一行,每一行是有序的,二分搜索

3.左下/右上(M+N):O(M+N) 右上是该行和该列(该元素所在列以上的元素)所有元素里最大,若target比该元素大,则只能向下移动一行,小的话则遍历当前行。每次可以剔除一行。

4.双折半:最差O(M*logN)(最差情况target在矩形中心,这时候性能和单折差不多),平均可以O(logM+logN), 和单折半类似,四个点,top,bottom,left,right,稍微复杂一点。首先上边界折半,位于终止点右边的矩形框内的元素都大于该终止点,因次大于target,可以剔除。然后下边界折半,相似的道理可以剔除左边的矩形框,然后左边界,右边界。有很多细节要考察的,特别要注意top和left更新过程中,不能出现小于原来值的情况。具体看注释吧。

5.十字分割法:将二维数组分成四个矩形,选中间的交叉点,左上矩形和右下矩形必然冲突,每次能剔除1/4的元素,然后对剩下三个区域递归,直到只剩一个元素。

三.源码

# 暴力
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        for arr in array:
            if target in arr:return True
        return False

#二分
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        for arr in array:
            low,high=0,len(arr)-1
            mid=(low+high)/2
            while low<=high:
                if target<arr[mid]:
                    high=mid-1
                elif target>arr[mid]:
                    low=mid+1
                else:return True
                mid=(low+high)/2
        return False

#左下/右上+折半
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        if not array[0]:return False
        m=len(array[0])-1
        for arr in array:
            if target>arr[m]:continue
            low,high=0,len(arr)-1
            mid=(low+high)/2
            while low<=high:
                if target==arr[mid]:
                    return True
                elif target>arr[mid]:
                    low=mid+1
                else:high=mid-1
                mid=(low+high)/2
        return False

# 双折
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        if not array[0]:return False
        top,bottom,left,right=0,len(array)-1,0,len(array[0])-1
        cur_top,cur_bottom,cur_left,cur_right=top,bottom,left,right
        while left<right or top<bottom:
            cur_left,cur_right=left,right
            # bin search top
            while cur_left<=cur_right:
                mid=(cur_left+cur_right)/2
                if target==array[top][mid]:return True
                elif target<array[top][mid]:cur_right=mid-1
                else:cur_left=mid+1
            # delete the right rectangle
            right=(cur_right+cur_left)/2
            top+=1
            cur_left,cur_right=left,right
            #bin search bottom
            while cur_left<=cur_right:
                mid=(cur_left+cur_right)/2
                if target==array[bottom][mid]:return True
                elif target<array[bottom][mid]:cur_right=mid-1
                else:cur_left=mid+1
            # delete the left rectangle
            # Attention:, since we use <= in while statement
            # this means that cur_right may less than cur_left
            # this can lead to (cur_right+cur_left)/2 less left
            # if we do not add this if statement, this lead to problems
            # left show never be smaller in iteration
            if (cur_right+cur_left)/2>left:left=(cur_right+cur_left)/2  
            bottom-=1
            # bin search left
            cur_top,cur_bottom=top,bottom
            while cur_top<=cur_bottom:
                mid=(cur_top+cur_bottom)/2
                if target==array[mid][left]:return True
                elif target<array[mid][left]:cur_bottom=mid-1
                else:cur_top=mid+1
            # delete the downward rectangle
            bottom=(cur_top+cur_bottom)/2
            left+=1
            # bin search right
            cur_top,cur_bottom=top,bottom
            while cur_top<=cur_bottom:
                mid=(cur_top+cur_bottom)/2
                if target==array[mid][right]:return True
                elif target<array[mid][right]:cur_bottom=mid-1
                else:cur_top=mid+1
            # delete the upward rectangle
            if (cur_top+cur_bottom)/2>top:top=(cur_top+cur_bottom)/2
            right-=1
        # Attention, in the outer while statement, we use <
        # not <=, thus we need to add one more judgement as 
        # there may be the case that after the last modification in
        # right-=1, array[top][right] is the target, but right<=left,
        # then we can judge this case in inner while statement.
        return True if array[top][right]==target else False

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值