Binary Search

Binary Search

二分查找是一种基于分治策略的高效搜索算法。它利用数据的有序性,每轮缩小一半搜索范围,直至找到目标元素或搜索区间为空为止。

  • Pros: 时间效率高,无需额外空间开销。
  • Cons: 仅适用于有序数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* 二分查找(双闭区间) */
int binarySearch(int[] nums, int target) {
    // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
    int i = 0, j = nums.length - 1;
    // 循环,当搜索区间为空时跳出(当 i > j 时为空)
    while (i <= j) {
        int m = i + (j - i) / 2; // 计算中点索引 m
        if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
            i = m + 1;
        else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
            j = m - 1;
        else // 找到目标元素,返回其索引
            return m;
    }
    // 未找到目标元素,返回 -1
    return -1;
}

/* 二分查找(左闭右开区间) */
int binarySearchLCRO(int[] nums, int target) {
    // 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
    int i = 0, j = nums.length;
    // 循环,当搜索区间为空时跳出(当 i = j 时为空)
    while (i < j) {
        int m = i + (j - i) / 2; // 计算中点索引 m
        if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
            i = m + 1;
        else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
            j = m;
        else // 找到目标元素,返回其索引
            return m;
    }
    // 未找到目标元素,返回 -1
    return -1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//寻找左侧边界的二分搜索
int left_bound(int[] nums, int target) {
    int left = 0;
    // 注意
    int right = nums.length;

    // 注意
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            // 注意
            right = mid;
        }
    }
    return left;
}
//寻找右侧边界的二分搜索
int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length;

    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            left = mid + 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    // 注意
    return left - 1;
}

Examples

34-在排序数组中查找元素的第一个和最后一个位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false);
        if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
            return new int[] { leftIdx, rightIdx };
        }
        return new int[] { -1, -1 };
    }

    public int binarySearch(int[] nums, int target, boolean lower) {
        int left = 0, right = nums.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid;
            } else if (nums[mid] == target) {
                if (lower) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
        }
        return lower ? left : left - 1;
    }
}

704-二分查找

Time Complexity $O(log_n)$
Space Complexity $O(1)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

875-爱吃香蕉的珂珂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {

    public int minEatingSpeed(int[] piles, int H) {
        int left = 1, right = 1;
        for (int pile : piles) {
            right = Math.max(right, pile);
        }

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (estimatedHours(piles, mid) > H) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    private int estimatedHours(int[] piles, int speed) {
        int hours = 0;
        for (int pile : piles) {
            hours += pile % speed == 0 ? pile / speed : pile / speed + 1;
        }
        return hours;
    }
}

1011-在 D 天内送达包裹的能力

1011,875两题区别

1011:对任意 i,有 capacity > weight[i],即一天至少运一箱货
875:对任意 i,有 pile[i] >= speed,即一小时最多吃一堆香蕉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
    public int shipWithinDays(int[] weights, int days) {
        int max = 0, sum = 0;
        for (int weight : weights) {
            max = Math.max(max, weight);
            sum += weight;
        }

        int left = max, right = sum;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (canDeliverWithinDays(weights, mid, days)) { // 对应mid[i] >= target
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    boolean canDeliverWithinDays(int[] weight, int capacity, int days) {
        int currentWeightSum = 0, cntOfDay = 1;

        for (int w : weight) {
            currentWeightSum += w;
            if (currentWeightSum > capacity) {
                currentWeightSum = w;
                cntOfDay++;
            }
        }
        return cntOfDay <= days;
    }
}

Ref

binary_search

作者

Jiaxing Gao

发布于

2024-09-12

更新于

2024-11-23

许可协议

评论

}