二分搜索(折半查找)是應用很廣泛的一種算法,當出現有序序列時,我們可以立馬想到能否可以用二分法,其寫法也較爲固定。我們可以把二分法視爲分治的應用。但是如果不注意其變換條件也是很容易寫錯。下邊給出了二分查找的非遞歸和遞歸寫法,只要注意其邊界判斷和變換,代碼很簡單:
二分法的遞歸和非遞歸寫法
package com.blog.binarysearch;
/**
* @Description: 二分法(二分搜索 折半查找) 有序序列的搜索 時間複雜度爲O(logn)
* @Author: Jingzeng Wang
* @Date: Created in 15:56 2017/7/23.
*/
public class BinarySearchDemo {
public static void main(String[] args) {
int[] nums = {1, 2, 3, 5, 7, 9, 11, 13};
System.out.println(binarySearch(nums, 11));
System.out.println(binarySearchRecursive(nums, 11, 0, nums.length - 1));
}
/**
* 二分 非遞歸版本
* <p>
* right = num.length left < right right = mid; 另一種寫法
*
* @param nums 已排序數組
* @param keyNum 待查找數字
* @return 返回查找的索引位置 沒有則返回-1
*/
public static int binarySearch(int[] nums, int keyNum) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
//int mid = start + (end - start) / 2; //直接平均可能溢出,可以用此算法
int mid = (left + right) / 2;
if (nums[mid] < keyNum) {
left = mid + 1;
} else if (nums[mid] > keyNum) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
/**
* 二分搜索的遞歸寫法
*
* @param nums
* @param value
* @param left
* @param right
* @return
*/
public static int binarySearchRecursive(int[] nums, int value, int left, int right) {
if (left > right)
return -1;
int mid = left + (right - left) / 2;
if (nums[mid] < value)
return binarySearchRecursive(nums, value, mid + 1, right);
else if (nums[mid] > value)
return binarySearchRecursive(nums, value, left, mid - 1);
else return mid;
}
}
二分法的變形應用
// hash表可以 遍歷也可以 但是排序數組肯定有用 二分啊
// 二分的變形:找正好大於k的那個數的位置 與 正好小於k 的位置 然後相減 時間複雜度爲 O(logn)
// 定位k第一次出現的位置 和 最後一次出現的位置
public class Solution {
public int GetNumberOfK(int [] array , int k) {
if (array == null || array.length <= 0) {
return 0;
}
int left = 0;
int right = array.length - 1;
int mid1 = (left + right) >> 1;
// 找第一個k
while (left <= right) {
if (array[mid1] >= k) {
right = mid1 - 1;
} else {
left = mid1 + 1; // < left 是始終指向小於k的 最後也是+1獲得第一個k
}
mid1 = (left + right) >> 1;
}
mid1 = left;
left = 0;
right = array.length - 1;
int mid2 = (left + right) >> 1;
//找最後一個k
while (left <= right) {
if (array[mid2] > k) {
right = mid2 - 1; // 大於k的 獲得最後一個k
} else {
left = mid2 + 1;
}
mid2 = (left + right) >> 1;
}
mid2 = right;
return mid2 - mid1 + 1;
}
}