每日一題 - 劍指 Offer 53 - I. 在排序陣列中查詢數字 I
阿新 • • 發佈:2020-07-05
### 題目資訊
- 時間: 2019-07-04
- 題目連結:[Leetcode](https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/)
- tag:二分查詢 雜湊表
- 難易程度:簡單
- 題目描述:
統計一個數字在排序陣列中出現的次數。
**示例1:**
```html
輸入: nums = [5,7,7,8,8,10], target = 8
輸出: 2
```
**示例2:**
```html
輸入: nums = [5,7,7,8,8,10], target = 6
輸出: 0
```
> 注意
```html
1. 0 <= 陣列長度 <= 50000
```
### 解題思路
>本題難點
排序陣列中查詢數字,效能最優。
>具體思路
排序陣列中的搜尋問題,首先想到 **二分法** 解決。
排序陣列 nums 中的所有數字 target 形成一個視窗,記視窗的 左 / 右邊界 索引分別為 left 和 right ,分別對應視窗左邊 / 右邊的首個元素。
統計數字 target 的出現次數,可轉化為:使用二分法分別找到 左邊界 left 和 右邊界 right ,易得數字 target 的數量為 right−left−1 。
- 計算中點 m=(i+j)/2(向下取整)
- 若 nums[m]target ,則 target 在閉區間 [i,m−1] 中,因此執行 j=m−1;
- 若 nums[m]=target ,則右邊界 right 在閉區間 [m+1,j] 中;左邊界 left 在閉區間 [i,m−1] 中。
- 若查詢 右邊界 right ,則執行 i=m+1 ;(跳出時 i指向右邊界)
- 若查詢 左邊界 left ,則執行 j=m−1 ;(跳出時 j指向左邊界)
> 提示:查詢完右邊界後,可用 nums[j]=j 判斷陣列中是否包含 target ,若不包含則直接提前返回 0 ,無需後續查詢左邊界。查詢完右邊界後,左邊界 left一定在閉區間 [0,j] 中,因此直接從此區間開始二分查詢即可。
### 程式碼
```java
class Solution {
public int search(int[] nums, int target) {
// 搜尋右邊界 right
int i = 0, j = nums.length - 1;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] <= target) i = m + 1;
else j = m - 1;
}
int right = i;
// 若陣列中無 target ,則提前返回
if(j > = 0 && nums[j] != target) return 0;
// 搜尋左邊界 right
i = 0;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] < target) i = m + 1;
else j = m - 1;
}
int left = j;
return right - left - 1;
}
}
```
**複雜度分析:**
- 時間複雜度 O(logN) : 二分法為對數級別複雜度。
- 空間複雜度 O(1) :幾個變數使用常數大小的額外空間。
### 其他優秀解答
> 解題思路
直接遍歷排序陣列,計數。
> 程式碼
```java
class Solution {
public int search(int[] nums, int target) {
int count = 0;
for(int num : nums){
if(num == target){
count++;
}
}
return count;