剑指Offer——查找算法

查找算法

Offer 04 二维数组中的查找

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

在这里插入图片描述
解题思路

若使用暴力法遍历矩阵 matrix ,则时间复杂度为 O(NM) 。暴力法未利用矩阵 “从上到下递增、从左到右递增”的特点,显然不是最优解法。

如下图所示,我们将矩阵逆时针旋转 45° ,并将其转化为图形式,发现其类似于二叉搜索树,即对于每个元素,其左分支元素更小、右分支元素更大。因此,通过从 “根节点” 开始搜索,遇到比 target 大的元素就向左,反之向右,即可找到目标值 target 。
在这里插入图片描述
在这里插入图片描述
算法流程

  1. 从矩阵 matrix 左下角元素(索引设为 (i, j) )开始遍历,并与目标值对比:
    在这里插入图片描述
  2. 若行索引或列索引越界,则代表矩阵中无目标值,返回 false 。

每轮 i 或 j 移动后,相当于生成了“消去一行(列)的新矩阵”, 索引(i,j) 指向新矩阵的左下角元素(标志数),因此可重复使用以上性质消去行(列)。

Python代码如下:

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        #左下角初始化i,j
        i, j = len(matrix) - 1, 0
        #从左下角开始遍历
        while i >= 0 and j < len(matrix[0]):
            #若matrix[i][j]大于目标值,则向上移动一个
            if matrix[i][j] > target: i -= 1
            #若matrix[i][j]小于目标值,则向右移动一个
            elif matrix[i][j] < target: j += 1
            #若matrix[i][j]等于目标值,则返回True
            else: return True
        #若行索引或列索引越界,则代表矩阵中无目标值,返回 false 
        return False

作者:jyd
来源:力扣(LeetCode)

Offer 11 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
在这里插入图片描述
解题思路
如下图所示,寻找旋转数组的最小元素即为寻找 右排序数组 的首个元素 numbers[x] ,称 x 为 旋转点 。
在这里插入图片描述
排序数组的查找问题首先考虑使用二分法解决

算法流程
在这里插入图片描述
Python代码如下:

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        #初始化i j,分别指向 numbers 数组左右两端
        i, j = 0, len(numbers)-1
        while i < j:
            #取中间值
            m = (i+j) // 2
            #若numbers[m] > numbers[j],m一定在左排序数组中,即旋转点x一定在 [m + 1, j]
            if numbers[m] > numbers[j]: i = m + 1
            #若numbers[m] < numbers[j],m一定在右排序数组中,即旋转点x一定在 [m, j]
            elif numbers[m] < numbers[j]: j = m
            #相等的话执行 j = j - 1 缩小判断范围
            else: j -= 1
        #当 i = j 时跳出二分循环,并返回旋转点的值 nums[i] 即可
        return numbers[i]

作者:jyd
来源:力扣(LeetCode)

Offer 50 第一个只出现一次的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
在这里插入图片描述
解题思路
1.遍历字符串 s ,使用哈希表统计 “各字符数量是否 >1 ”
2.再遍历字符串 s ,在哈希表中找到首个 “数量为 1 的字符”,并返回
在这里插入图片描述
算法流程

  1. 初始化: 字典记为 dic ;
  2. 遍历字符串 s 中的每个字符 c:
    1.若 dic 中 不包含 键(key) c :则向 dic 中添加键值对 (c, True) ,代表字符 c 的数量为 1 ;
    2.若 dic 中 包含 键(key) c :则修改键 c 的键值对为 (c, False) ,代表字符 c 的数量 >1 。
  3. 查找数量为 1 的字符: 遍历字符串 s 中的每个字符 c ;
    1.若 dic中键 c 对应的值为 True ,则返回 c 。
  4. 返回 ’ ',代表字符串无数量为 1 的字符。

Python代码如下:

class Solution:
    def firstUniqChar(self, s: str) -> str:
        #初始化dic字典
        dic = {}
        #遍历字符串s的每个字符
        for c in s:
            #not c in dic 整体为一个布尔值; c in dic 为判断字典中是否含有键 c
            dic[c] = not c in dic
        for c in s:
            #遍历中出现首位直接返回c
            if dic[c]: return c
        #如果没有,返回一个单空格
        return ' '

作者:jyd
来源:力扣(LeetCode)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值