題目資訊
-
時間: 2019-07-04
-
題目連結:Leetcode
-
tag:二分查詢 雜湊表
-
難易程度:簡單
-
題目描述:
統計一個數字在排序陣列中出現的次數。
示例1:
輸入: nums = [5,7,7,8,8,10], target = 8
輸出: 2
示例2:
輸入: nums = [5,7,7,8,8,10], target = 6
輸出: 0
注意
1. 0 <= 陣列長度 <= 50000
解題思路
本題難點
排序陣列中查詢數字,效能最優。
具體思路
排序陣列中的搜尋問題,首先想到 二分法 解決。
排序陣列 nums 中的所有數字 target 形成一個視窗,記視窗的 左 / 右邊界 索引分別為 left 和 right ,分別對應視窗左邊 / 右邊的首個元素。
統計數字 target 的出現次數,可轉化為:使用二分法分別找到 左邊界 left 和 右邊界 right ,易得數字 target 的數量為 right−left−1 。
- 計算中點 m=(i+j)/2(向下取整)
- 若 nums[m]<target ,則 target 在閉區間 [m+1,j] 中,因此執行 i=m+1;
- 若 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] 中,因此直接從此區間開始二分查詢即可。
程式碼
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) :幾個變數使用常數大小的額外空間。
其他優秀解答
解題思路
直接遍歷排序陣列,計數。
程式碼
class Solution {
public int search(int[] nums, int target) {
int count = 0;
for(int num : nums){
if(num == target){
count++;
}
}
return count;
}
}