力扣剑指Offer 第5天 查找算法(中等) 剑指 Offer 04. 二维数组中的查找 剑指 Offer 11. 旋转数组的最小数字 剑指 Offer 50. 第一个只出现一次的字符

本文介绍剑指Offer中的三道查找题:二维数组中的查找、旋转数组的最小数字及第一个只出现一次的字符。提供了详细的解题思路与代码实现。

力扣剑指Offer 第5天 查找算法(中等) 剑指 Offer 04. 二维数组中的查找 剑指 Offer 11. 旋转数组的最小数字 剑指 Offer 50. 第一个只出现一次的字符

剑指 Offer 04. 二维数组中的查找

题目

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

示例:

现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

给定 target = 5,返回 true

给定 target = 20,返回 false

思路

原本我想从中间开始搜索,类似二分一样的去处理,但是这样考虑将会非常复杂。

但是如果从某个角落开始,利用每一个方向都有着变大或变小的固定规则来进行二分选择,高效率又简单编写。

这个角落只能是左下角或右上角(符合一个方向递增一个方向递减的规则),利用这个规则利用当前位置的值与target比较,如果相等说明存在,大于则往递减方向移动,小于则往递增方向移动,如果移动到了边界还没有找到target则说明不存在。

代码

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix.length==0)return false;//特判是否为空
        int rows = matrix.length,cols = matrix[0].length;
        int r=rows-1,c=0;
        while(r>=0&&r<rows&&c>=0&&c<cols){
                if(matrix[r][c]>target)r--;
                else if(matrix[r][c]<target)c++;
                else return true;
        }
        return false;
    }
}

☆剑指 Offer 11. 旋转数组的最小数字

题目

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2][1,2,3,4,5]的一个旋转,该数组的最小值为1。

示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0

思路(比较难!)

  1. 判断是否旋转了(首元素与末尾元素比大小即可)
  2. 如果没有旋转(首元素<末尾元素)return numbers[0]
  3. 如果旋转了(首元素>末尾元素)二分搜索 (numbers[m]与number[r]比较 小则往左 大则往右)
    1. if(numbers[m]<number[r])r=m
    2. if(numbers[m]>number[r])l=m+1
    3. if(number[m]==number[r])r=r-1

为什么与number[r]比较?

[已旋转]由上述思路可知,当到达第3步的时候可以确定是已经旋转的数组。

以下是numbers[m]==numbers[r]后r—的所有情况

  1. [001|0] 跳跃转折点 -> [001|] 此时 numbers[r]为左边最大值 一直向左 找到最小值
  2. [1111]全部相同 一直r–直到 最左
  3. [0001|00] 最后会转向情况1
  4. [1111|011]最后会转向情况5
  5. [11|01] 未跳跃转折点

从以上可知r–1不会影响判断的内容

代码

class Solution {
    public int minArray(int[] numbers) {
        if(numbers.length==1)return numbers[0];//只有一个数
        int l=0,r=numbers.length-1,m;
        if(numbers[0]<numbers[r])return numbers[0];//没有旋转(加快判断)
        while(l<r){
            m=(l+r)>>1;
            if(numbers[m]<numbers[r])r=m;
            else if(numbers[m]>numbers[r])l=m+1;
            else r--;
        }
        return numbers[l];
    }
}

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

思路

用set来判断是否已经是第一次出现该字符

  1. 如果是第一次出现则向动态数组后面添加该字符
  2. 不是第一次则删除动态数组中的该字符(没有则啥也不发生)

代码

class Solution {
    public char firstUniqChar(String s) {
        Set<Character> set=new HashSet<>();
        ArrayList<Character> a=new ArrayList<>();
        int len = s.length();
        for(int i=0;i<len;i++){
            Character c = s.charAt(i);
            if(!set.contains(c)){
                set.add(c);
                a.add(c);
            }else a.remove(c);
        }
        if(!a.isEmpty())return a.get(0);
        return ' ';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值