검색 캐럿 위치
1. 주제
Leetcode 링크
정렬된 배열과 대상 값이 주어지면 배열에서 대상 값을 찾고 해당 인덱스를 반환합니다. 대상 값이 배열에 없으면 순서대로 삽입할 위치를 반환합니다.
시간 복잡도가 O(log n)인 알고리즘을 사용하십시오.
예 1:
입력: 숫자 = [1,3,5,6], 대상 = 5
출력: 2
예 2:
입력: 숫자 = [1,3,5,6], 대상 = 2
출력: 1
예 3:
입력: 숫자 = [1,3,5,6], 대상 = 7
출력: 4
예 4:
입력: 숫자 = [1,3,5,6], 대상 = 0
출력: 0
예 5:
입력: 숫자 = [1], 대상 = 0
출력: 0
힌트:
- 1 <= 숫자.길이 <= 104
- -104 <= 숫자[i] <= 104
- nums는 반복되는 요소가 없는 오름차순 배열입니다.
- -104 <= 대상 <= 104
2. 아이디어
제목은 이분법을 사용하라는 메시지를 표시합니다.
- nums는 반복되는 요소가 없는 오름차순 배열입니다.
- 시간 복잡도가 O(log n)인 알고리즘을 사용해야 합니다.
네 가지 상황:
- 대상 값은 배열의 모든 요소 앞에 있습니다.
- 대상 값이 배열의 요소와 같습니다.
- 대상 값이 삽입되는 배열의 위치
- 대상 값은 배열의 모든 요소 뒤에 있습니다.
핵심:
- 순회를 종료하기 위해 바이너리 방법을 사용하는 경우 왼쪽과 오른쪽이 가리키는 위치
3. 코드 구현
3.1 해결책 1: 폭력적인 해결책
- 시간 복잡도 O(log n) 조건을 만족하지 않음
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for(int i = 0; i < nums.size(); i++){
// 对应于前三种情况
if(nums[i] >= target){
return i;
}
}
// 对应于目标值在数组所有元素之后的情况
return nums.size();
}
};
3.2 솔루션 2: 이분법(왼쪽 폐쇄 및 오른쪽 폐쇄)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
// 定义左闭右闭区间
int left = 0;
int right = nums.size() - 1;
while(left <= right){
int middle = left + (right - left) / 2;
if(nums[middle] < target){
left = middle + 1; // target 在右区间,所以[middle + 1, right]
}else if(nums[middle] > target){
right = middle - 1; // target 在左区间,所以[left, middle - 1]
}else{
// nums[middle] == target
return middle;
}
}
// 数组中不存在target
// 1. 插入到所有元素之前,所有的元素都比target大:right = -1(left = 0)
// 2. 插入到数组中,nums[left] < target < nums[right]
// 下一次循环,执行left = middle + 1;
// 下一次循环,执行right = middle - 1, 结束循环;
// 3. 插入到所有元素之后,所有的元素都比target大:right = nums.size() - 1(left = nums.size())
return right + 1;
}
};
3.3 솔루션 3: 이분법(왼쪽 폐쇄 및 오른쪽 개방)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
// 定义左闭右开区间
int left = 0;
int right = nums.size();
while(left < right){
int middle = left + (right - left) / 2;
if(nums[middle] < target){
left = middle + 1; // target 在右区间,所以[middle + 1, right)
}else if(nums[middle] > target){
right = middle; // target 在左区间,所以[left, middle)
}else{
// nums[middle] == target
return middle;
}
}
// 数组中不存在target
// 1. 插入到所有元素之前,所有的元素都比target大:right = 0(left = 0)
// 2. 插入到数组中,nums[left] < target < nums[right]
// 下一次循环,执行left = middle + 1;
// 下一次循环,执行right = middle, 结束循环;
// 3. 插入到所有元素之后,所有的元素都比target大:right = nums.size()(left = nums.size())
return right;
}
};
4. 요약
- 이분법 과정에 대한 이해를 깊게 할 필요가 있으며, 특히 루프가 끝날 때 왼쪽과 오른쪽의 포인팅 위치