朴素解法

一个朴素的解法是直接对 进行线性扫描,当第一次遇到 说明找到了答案。

代码:

import java.util.*;

public class Solution {
    public int search (int[] nums, int target) {
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (nums[i] == target) return i;
        }
        return -1;
    }
}
  • 时间复杂度:
  • 空间复杂度:

二分

上述解法没有利用到数组有序的特性,利用元素有序的特性,我们可以使用「二分」来查找目标值。

但「二分」有一个比较容易混淆的点是:当需要找目标值第一次出现的下标时,条件应该写成 nums[mid] >= target 还是 nums[mid] <= target

强记模板是没有意义的,我们需要搞清楚到底在「二分」什么:

由于二分是从中间开始找起的,所以找的必然是条件区间中靠近中心的的边界值。

文字不好理解,我们结合图片来看:

640.png

代码:

import java.util.*;

public class Solution {
    public int search (int[] nums, int target) {
        int n = nums.length;
        if (n == 0) return -1;
        int l = 0, r = n - 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        return nums[r] == target ? r : -1;
    }
}
  • 时间复杂度:
  • 空间复杂度:

拓展(找首尾)

如果将问题进一步拓展,要求输出 中的「第一个」和「最后一个」位置 的话,该如何求解?

其实还是一样的,只需要抓住「二分」的本质即可:

640.png

显然,当我们想二分出「第一个」位置时,check 判断应该写成 nums[mid] >= target;而当二分出「最后一个」位置时,check 判断应该写成 nums[mid] <= target

代码:

class Solution {
    public int[] search(int[] nums, int target) {
        int[] ans = new int[]{-1, -1};
        int n = nums.length;
        if (n == 0) return ans;

        // 第一次二分:求 target 第一次出现的位置
        int l = 0, r = n - 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (nums[mid] >= target) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        if (nums[l] != target) {
            return ans;
        } else {
            ans[0] = l;
            // 第二次二分:求 target 最后一次出现的位置
            l = 0; r = n - 1;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (nums[mid] <= target) {
                    l = mid;
                } else {
                    r = mid - 1;
                }
            } 
            ans[1] = l;
            return ans;
        }
    }
}
  • 时间复杂度:
  • 空间复杂度:

最后

这是我们「必考真题 の 精选」系列文章的第 No.105 篇,系列开始于 2021/07/01。

该系列会将牛客网中「题霸 - 面试必考真题」中比较经典而又不过时的题目都讲一遍。

在提供追求「证明」&「思路」的同时,提供最为简洁的代码。

欢迎关注,交个朋友 (`・ω・´)