剑指offer笔记(1):二维数组中的查找

题目描述

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

分析

首先分析题意,它要求我们给一个二维数组,并且每行每列都是递增的等长度数组,所以我们自然而然想到一个最简单的矩阵为:

( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ) \begin{pmatrix} 1&2 &3 &4 \\ 5&6 &7 &8 \\ 9&10 &11 &12 \\ 13&14 &15 &16 \end{pmatrix} 15913261014371115481216
上面这个矩阵满足题目所有的要求,在程序里可以这样定义:

import numpy as np
array = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])

思路一:循环遍历

所以我们可以针对这个矩阵进行下一步的分析,首先我想到的是通过遍历去获取target,那么很显然,遍历完数据就可以直接找值了:

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        row=len(array)
        col=len(array[0])
        for i in range(row):
            for j in range(col):
                if array[i][j]==target:
                    return True
        return False

这种相当于直接暴力求解,技术点一般,如果是在慕课网,我感觉应该是通不过的。


思路二:二分查找

既然想到了全部遍历,那肯定还会有更快的代码,所以我就点进了讨论里看了下大佬们java和C的代码,看到了一份java版的二分法,就准备开始自己尝试。

python二分法伪代码

#encoding: utf-8
def half_search(search_arr, search_str):
  lb = 0
  ub = len(search_arr) - 1
  for i in range(ub/2 + 1):
    if lb > ub:
      return -1
    mid = (ub + lb)/2
    if search_arr[mid] == search_str:
      return mid
    elif search_arr[mid] > search_str:
      ub = mid - 1
    else:
      lb = mid + 1

上述是伪代码,然后我们就能写出本题的二分查找:

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # col = len(array[0])
        cow = len(array[0]) - 1
        for i in range(len(array)):
            col = 0
            print(i)
            while col < cow:
                mid = int((cow + col) / 2)
                if target > array[i][mid]:
                    col = mid + 1
                elif target < array[i][mid]:
                    cow = mid - 1
                else:
                    return True
        return False

中间改写的时候出了很多新的错误,在这里记录一下:

  1. (only integer scalar arrays can be converted to a scalar index)只有整数标量数组才能转换成标量索引,是我在遍历的时候没有计算长度
  2. (only integers, slices (:), ellipsis (...), numpy.newaxis (None) and integer or boolean arrays are valid indices) ,mid = int((cow + col) / 2),我没有加int
  3. 另外就是如果索引没有减1,会出现索引错误,但遍历的时候不需要减1,刚开始搞混了,让我一度怀疑是不是python解释器有问题,找不到真实的地址。。。

思路三:判断角标

首先看二维数组中右上角的数字,如果该数字等于要查找的数字,则查找结束;如果该数字大于要查找的数字,则剔除这一列;如果该数字小于要查找的数字,则剔除该数字所在的行。

我们可以用图形说明:
在这里插入图片描述

然后我们就能编写代码:

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        rows = len(array)
        cols = len(array[0])
        if rows > 0 and cols > 0:
            row = 0
            col = cols - 1
            while row < rows and col >= 0:
                if target == array[row][col]:
                    return True
                elif target < array[row][col]:
                    col -= 1
                else:
                    row += 1
        return False

第三种是看了别人代码,然后自己照着实现了一下,总结本题,还是思路二花的时间多,有些东西还是不熟。

思路四:使用numpy内置方法

此方法在牛客网调节不出来,但确实可以运行成功。

首先在我们的python中,对于遍历来讲,不如C、Java和MATLAB一样,可以用一个for循环显示全部,前两者因为比较深入底层,可以根据字节地址偏移来实现,后者本身就是偏向于数学工程,数组构成方式有些不一样。

但python里没有指针的概念,所以所有的指针功能都是通过引用实现的,这就导致了python的执行效率会降低,另外就是可能我们定义的变量并不是真实的指针地址,而是中间多了一层引用,所以我们无法对我们定义的数组空间做任何修改。可按照常理来讲,一个for循环为什么不能遍历全部数据?这里就要提及numpy中的flat方法了:

import numpy as np
import pandas as pd
array = np.array([[1,2,3],[4,5,6],[7,8,9]])

class Solution:
    # array 二维列表
    def Find(self, target, array):
        # col = len(array[0])
        for element in array.flat:
            if target == element:
                return True
        return False

s = Solution()
s.Find(6,array)
"""
True
"""

另外还有flatten方法,将多维数组转化为一维数组:

array1 = array.flatten(order="C")
array1
"""
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
"""

关于更详细的解释,可以看下面的链接:
numpy中flat/flatten用法区别

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值