LeetCode 알고리즘 C++ 브러시 질문-searchFirstLastEqualElement

오늘의 질문

오름차순의 정수 배열 nums와 대상 값 대상이 주어집니다. 배열에서 주어진 대상 값이 시작하는 위치를 찾으십시오.

그리고 끝 위치. 알고리즘 시간 복잡도는 O(log n) 수준이어야 합니다. 대상 값이 배열에 없으면 [-1, -1]을 반환합니다.

예 1:

입력: 숫자 = [5,7,7,8,8,10], 대상 = 8
출력: [3,4]

예 2:

입력: 숫자 = [5,7,7,8,8,10], 대상 = 6
출력: [-1,-1]

문제 해결 아이디어:


정렬된 배열 nums 및 숫자 목표가 주어지면 배열에서 이 요소와 동일한 첫 번째 요소 인덱스를 찾고 이 요소 와 동일한 마지막 요소 인덱스를 찾아야 합니다 .
이 질문은 고전적인 이진 검색 변형입니다. 이진 검색에는 4가지 기본 변형이 있습니다.

  1. 값이 주어진 값과 같은 첫 번째 요소를 찾습니다.
  2. 값이 주어진 값과 같은 마지막 요소를 찾습니다.
  3. 주어진 값보다 크거나 같은 첫 번째 요소 찾기
  4. 주어진 값보다 작거나 같은 마지막 요소 찾기

이 질문에 대한 문제 해결 아이디어는 각각 변형 1과 변형 2의 솔루션을 사용하여 해결할 수 있습니다. 또는 변형 1의 방법을 한 번 사용한
다음 뒤로 루프하여 주어진 값과 동일한 마지막 요소를 찾습니다.
그러나 후자의 방법 은 배열의 n개의 요소가 주어진 요소와 모두 같을 가능성이 있기 때문에 시간 복잡도를 O(n)으로 줄일 수 있습니다 . (4가지 기본 변형 구현에 대한 코드 참조)

샘플 코드:

class searchFirstLastEqualElement{
    
    
public:
    vector<int> searchRange(vector<int>& nums, int target) {
    
    
        vector<int> res(-1,-1);
        if(nums.empty()) return res;
        int n = nums.size(),left = 0, right = n-1;
        while(left <= right)
        {
    
    
            int m = left + (right - left)/2;
            if(nums[m] > target){
    
    
                right = m - 1;
            }else if(nums[m] < target){
    
    
                left = m + 1;
            } else {
    
    
				if(m = 0 || num[m-1] != target) {
    
    
					res[0] = m;
					return res;
				}
				right = m - 1;
			}
        }
        
        while(left <= right)
        {
    
    
            int m = left + (right - left)/2;
            if(nums[m] > target){
    
    
                right = m - 1;
            }else if(nums[m] < target){
    
    
                left = m + 1;
            } else {
    
    
				if(m == n -1 || nums[m+1] != targrt) {
    
    
					res[1] = m;
					return res;
				}
				low = m + 1;
			}
        }

        return res;
    }
};

예비 지식: 이분법

1. 이분법의 전제

1. 배열이 정렬된 배열인 경우
2. 배열에 반복되는 요소가 없는 경우(일단 반복되는 요소가 있으면 이진 검색 방법으로 반환되는 요소의 첨자가 고유하지 않을 수 있음) 위의 상황에 해당 주제.

2. 내용

이분법의 논리는 매우 간단합니다. 간격의 정의를 명확히 하십시오.
이분법에서 구간의 정의는 일반적으로 왼쪽 닫힘과 오른쪽 닫힘[왼쪽, 오른쪽] 또는 왼쪽 닫힘 오른쪽 열림[왼쪽, 오른쪽]의 두 가지 정의가 있습니다.

(1) 왼쪽 닫힘 오른쪽 닫힘 [왼쪽, 오른쪽]
class Solution {
    
    
public:
    int search(vector<int>& nums, int target) {
    
    
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) {
    
     // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
    
    
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
    
    
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else {
    
     // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
(2) 왼쪽 닫힘 오른쪽 열림 [왼쪽, 오른쪽)
class Solution {
    
    
public:
    int search(vector<int>& nums, int target) {
    
    
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) {
    
     // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
    
    
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
    
    
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else {
    
     // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

위의 두 가지 상황에서 매우 간단하다고 할 수 있으며, 올바른 경계가 닫혀 있는지 여부와 값을 가져갈 수 있는지 여부에 주목하는 것 이상입니다.

Supongo que te gusta

Origin blog.csdn.net/u010196944/article/details/127609944
Recomendado
Clasificación