剑指OFFER-二维数组中的查找

Question

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

关键词:数组 有序 二分查找

Solution

1、暴力破解

时间复杂度:O(N^N)
空间复杂度:O(1)

  • Python
# array 二维列表
# target 目标值
def Find(self, target, array):
    if len(array)==0 or len(array[0])==0:
        return False
    for i in range(len(array)):
        for j in range(len(array[0])):
            if array[i][j] == target:
                return True
    return False
  • C++
// array 二维列表
// target 目标值
bool Find(int target, vector<vector<int> > array) {
    int row = array.size();
    int col = array[0].size();
    if(row==0||col==0) 
    	return false;
    int i, j;
    for(i=0; i<row; i++){
    	for(j=0; j<col; j++){
            if (target==array[i][j])
                return true;
            };
		};
    return false;
    };

2、二分查找

a、逐行二分查找

时间复杂度:O(NlogN)
空间复杂度:O(1)

  • Python
# array 二维列表
# target 目标值
def Find(self, target, array):
    if len(array)==0 or len(array[0])==0:
        return False
    for i in range(len(array)):
        left = 0
        right = len(array[0]) - 1
        while(left <= right):
            j = (left + right) // 2
            if target == array[i][j]:
                return True
            if target > array[i][j]:
                left = j + 1
            else :
                right = j - 1
    return False
  • C++
// array 二维列表
// target 目标值
bool Find(int target, vector<vector<int> > array) {
    int row = array.size();
    int col = array[0].size();
    if(row==0||col==0) 
    	return false;
    int i, j;
    int left, right;
    for(i=0; i<row; i++){
    	for(left = 0, right = col-1; left <= right;){
            j = (left + right) / 2;
            if (target==array[i][j])
                return true;
            if (target > array[i][j]){
                left = j+1;
                continue;
                };
            if (target < array[i][j]){
                right = j-1;
                continue;
                };
            };
		};
    return false;
	};

b、二维折半查找

时间复杂度:O(NlogN)
空间复杂度:O(1)

  • Python
# array 二维列表
# target 目标值
def Find(self, target, array):
    if len(array)==0 or len(array[0])==0:
        return False
    top = left = 0
    bottom = len(array) - 1
    right = len(array[0]) - 1
    while(top<bottom or left<right):
        # 第一行缩小右边界
        rleft, rright = left, right
        while (rleft<=rright):
            j = (rleft + rright) // 2
            if array[top][j] == target:
                return True
            elif array[top][j] > target:
                rright = j - 1
            else:
                rleft = j + 1
        right = min(j, right)
        top += 1
        #最后一行缩小左边界
        rleft, rright = left, right
        while (rleft<=rright):
            j = (rleft + rright) // 2
            if array[bottom][j] == target:
                return True
            elif array[bottom][j] > target:
                rright = j - 1
            else:
                rleft = j + 1
        left = max(j, left)
        bottom -= 1
        #最左列缩小下边界
        ctop, cbottom = top, bottom
        while (ctop<=cbottom):
            i = (ctop + cbottom) // 2
            if array[i][left] == target:
                return True
            elif array[i][left] > target:
                cbottom = i - 1
            else:
                ctop = i + 1
        bottom = min(i, bottom)
        left += 1
        #最右列缩小上边界
        ctop, cbottom = top, bottom
        while (ctop<=cbottom):
            i = (ctop + cbottom) // 2
            if array[i][right] == target:
                return True
            elif array[i][right] > target:
                cbottom = i - 1
            else:
                ctop = i + 1
        top = max(i, top)
        right -= 1
    top = min(len(array)-1, top)
    left = min(len(array[0])-1, left)
    return array[top][left] == target
  • C++
// array 二维列表
// target 目标值
bool Find(int target, vector<vector<int> > array) {
    int row = array.size();
    int col = array[0].size();
    if(row==0||col==0) 
        return false;
    int top = 0;
    int left = 0;
    int bottom = row - 1;
    int right = col - 1;
        
    int rleft, rright, ctop, cbottom;
    int i, j;
    for(;top<bottom || left<right;){
        // 第一行缩小右边界
        rleft = left;
        rright = right;
        while (rleft<=rright){
            j = (rleft + rright) / 2;
            if (array[top][j] == target)
                return true;
            else if (array[top][j] > target)
                rright = j - 1;
            else
                rleft = j + 1;
        };
        if (j < right)
            right = j;
        top++;
        // 最后一行缩小左边界
        rleft = left;
        rright = right;
        while (rleft<=rright){
            j = (rleft + rright) / 2;
            if (array[bottom][j] == target)
                return true;
            else if (array[bottom][j] > target)
                rright = j - 1;
            else
                rleft = j + 1;
        };
        if (j > left)
            left = j;
        bottom--;
        // 最左列缩小下边界
        ctop = top;
        cbottom = bottom;
        while (ctop<=cbottom){
            i = (ctop + cbottom) / 2;
            if (array[i][left] == target)
                return true;
            else if (array[i][left] > target)
                cbottom = i - 1;
            else
                ctop = i + 1;
        };
        if (i < bottom)
            bottom = i;
        left++;
        // 最右列缩小上边界
        ctop = top;
        cbottom = bottom;
        while (ctop<=cbottom){
            i = (ctop + cbottom) / 2;
            if (array[i][right] == target)
                return true;
            else if (array[i][right] > target)
                cbottom = i - 1;
            else
                ctop = i + 1;
        };
        if (i > top)
            top = i;
        right--;
    };
        
    if (top> row - 1)
        top = row - 1;
    if (left > col - 1)
        left = col - 1;  
    return array[top][left] == target;
};

c、中心二分查找

时间复杂度:O(logN^2)
空间复杂度:O(1)

  • Python
# array 二维列表
# target 目标值
def Find(self, target, array):
    if len(array)==0 or len(array[0])==0:
        return False
        
    def search(top, bottom, left,right):
        if top>bottom or left>right:
            return False
        if top==bottom and left==right:
            return (array[top][left]==target)
        i = (top + bottom) // 2
        j = (left + right) // 2
        flag = False
        if array[i][j] == target or array[top][left] == target:
            return True
        # target小于中心点
        if array[i][j] > target:
            # 上方区域
            if target == array[top][left] or target == array[i-1][right]:
                return True
            elif array[top][left]<target and array[i-1][right]>target:
                flag = search(top, i-1, left, right)
            #左下区域
            if not flag:
                if target == array[i][left] or target == array[bottom][j-1]:
                    return True
                elif array[i][left]<target and array[bottom][j-1]>target:
                    flag = search(i, bottom, left, j-1)
            return flag

        # target大于中心点
        else:
            # 右上区域
            if target == array[top][j+1] or target == array[i][right]:
                return True
            elif array[top][j+1]<target and array[i][right]>target:
                flag = search(top, i, j+1, right)
            #下方区域
            if not flag:
                if target == array[i+1][left] or target == array[bottom][right]:
                    return True
                elif array[i+1][left]<target and array[bottom][right]>target:
                    flag = search(i+1, bottom, left, right)
            return flag
   
    return search(0, len(array)-1, 0, len(array[0])-1)
  • C++
// array 二维列表
// target 目标值
bool Find(int target, vector<vector<int> > array) {
    int row = array.size();
    int col = array[0].size();
    if(row==0||col==0) 
        return false;
    return search( array, target, 0, 0, col-1, row-1);
};
    
bool search(vector<vector<int> > &datas, int target, int left, int top, int right, int bottom){
    if (top == bottom && left == right)
        return datas[top][left] == target;
    else if (datas[top][left]>target || datas[bottom][right]<target)
        return false;
    else {
        int cHoriz = (left + right) / 2;
        int cVertic = (top + bottom) / 2;
 
        if (datas[cVertic][cHoriz] == target)
            return true;
        else {
                // 目标大于分割点则排除左上区域,对右下进行递归
            if (datas[cVertic][cHoriz] < target) {
                if (cHoriz<right && cVertic<bottom &&
                    search(datas, target, cHoriz+1, cVertic+1, right, bottom))
                    return true;
            }
            // 否则排除右下区域,对左上进行递归
            else if ((left<cHoriz || top<cVertic) &&
                     search(datas, target, left, top, cHoriz, cVertic))
                return true;
            // 对右上区域进行递归
            if (cHoriz < right &&
                search(datas, target, cHoriz+1, top, right, cVertic))
                return true;
            // 对左下区域进行递归
            if (cVertic < bottom &&
                search(datas, target, left, cVertic+1, cHoriz, bottom))
                return true;
            return false;
        }
    }
};

3、左下/右上移动元素

从左下角开始,若目标大于当前值,目标区域为当前值右边区域;若小于当前值,目标区域为上方区域。

时间复杂度:O(N)
空间复杂度:O(1)

  • Python
## 左下开始移动
# array 二维列表
# target 目标值
def Find(target, array):
    if len(array)==0 or len(array[0])==0:
        return False
    i = len(array)-1
    j = 0
    while i>=0 and j<len(array[0]):
        if target == array[i][j]:
            return True
        elif target > array[i][j]:
            j += 1
        else:
            i -= 1
    return False
  • C++
// 左下开始移动
// array 二维列表
// target 目标值
bool Find(int target, vector<vector<int> > array) {
    int row = array.size();
    int col = array[0].size();
    if (row == 0 || col == 0) 
    	return false;
    int i, j;
    for(i = row-1, j = 0; i>=0 && j < col;){
    	if(target == array[i][j])
    		return true;
    	if(target > array[i][j]){
    		j++;
    		continue;
    		}
    	if(target < array[i][j]){
    		i--;
    		continue;
    		}
		};
    return false;
    };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值