이진 검색
1. 주제
Leetcode 링크
n개의 요소와 대상 값 target이 있는 정렬된(오름차순) 정수 배열 nums가 주어지면 nums에서 대상을 검색하는 함수를 작성하고 대상 값이 존재하면 아래 첨자를 반환하고 그렇지 않으면 -1을 반환합니다.
입력: nums = [-1,0,3,5,9,12], target = 9
출력: 4
설명: 9는 첨자 4와 함께 nums에 나타납니다.
입력: nums = [-1,0,3,5,9,12], target = 2
출력: -1
설명: nums에는 2가 없으므로 -1을 반환합니다.
2. 아이디어
이분법 사용의 전제 : 정렬된 배열 + 배열에 중복 요소 없음
일반적으로 이분 간격의 두 가지 정의가 있습니다 . 왼쪽이 닫히고 오른쪽이 닫힘[왼쪽, 오른쪽] 또는 왼쪽이 닫히고 오른쪽이 열림[왼쪽, 오른쪽]
3. 코드 구현
3.1 쓰기 방법 1: 왼쪽 닫힘 및 오른쪽 닫힘
class Solution {
public:
int search(vector<int>& nums, int target) {
// 定义初始左闭右闭区间[left, right]
int left = 0;
int right = nums.size() - 1;
// 进行区间遍历,注意左闭右闭的区间对应的是<=
while(left <= right){
// middle的防止溢出写法,等同于(right+left) / 2
int middle = left + (right - left) / 2;
// 分成三种情况
if (nums[middle] > target){
right = middle - 1; // 新的区间落入原来的左半区间
}
else if (nums[middle] < target){
left = middle + 1; // 新的区间落入原来的右半区间
}
else{
return middle; // nums[middle] == target
}
}
return -1; // 未找到目标值
}
};
3.2 쓰기 방법 2: 왼쪽 닫힘 및 오른쪽 열림
class Solution {
public:
int search(vector<int>& nums, int target) {
// 定义初始左闭右开区间[left, righ)
int left = 0;
int right = nums.size() ;
// 进行区间遍历,注意左闭右开的区间对应的是<,因为取不到“right”对应位置的元素
while(left < right){
// middle的防止溢出写法,等同于(right+left) / 2
int middle = left + (right - left) / 2;
// 分成三种情况,注意要带着左闭右开的区间思想[left, right)
if (nums[middle] > target){
right = middle ; // 新的区间落入原来的左半区间, 右开, [left, middle)
}
else if (nums[middle] < target){
left = middle + 1; // 新的区间落入原来的右半区间, 左闭, [middle + 1, right)
}
else{
return middle; // nums[middle] == target
}
}
return -1; // 未找到目标值
}
};
4. 요약
4.1 오버플로 방지 쓰기 방법
// middle的防止溢出写法,等同于(right+left) / 2
int middle = left + (right - left) / 2;
4.2 배열 길이의 패리티
- 배열이 홀수인지 짝수인지에 관계없이 전체 배열은 배열의 길이에 따라 순회됩니다.
- 배열 길이 패리티의 영향은 중간 위치 값에 반영, (오른쪽+왼쪽) / 2
4.3 이분법의 핵심: 구간 정의 파악
- 검색 구간의 정의에 따라 경계 처리를 합니다.
- 구간의 정의는 불변이므로 루프 내에서 검색 구간의 정의에 따라 경계처리를 하도록 주장하는 것이 루프 불변의 법칙이다.