Algorithm/LeetCode
[LeetCode] 34. Find First and Last Position of Element in Sorted Array
Jaime.Lee
2023. 7. 15. 23:54
Problem
Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value.
If target is not found in the array, return [-1, -1].
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
Example 3:
Input: nums = [], target = 0
Output: [-1,-1]
Constraints:
- 0 <= nums.length <= 10^5
- -10^9 <= nums[i] <= 10^9
- nums is a non-decreasing array.
- -10^9 <= target <= 10^9
Solution
감소하지 않는 순서로 정렬된 배열이 주어질 때, 목표 값의 시작과 끝을 찾아서 반환하는 문제입니다.
package io.lcalmsky.leetcode.find_first_and_last_position_of_element_in_sorted_array;
public class Solution {
public int[] searchRange(int[] nums, int target) {
int start = firstGreaterEqual(nums, target); // 1
if (start == nums.length || nums[start] != target) { // 2
return new int[]{-1, -1};
}
int end = firstGreaterEqual(nums, target + 1) - 1; // 3
return new int[]{start, end}; // 4
}
private int firstGreaterEqual(int[] nums, int target) { // 5
int low = 0, high = nums.length; // 6
while (low < high) { // 7
int mid = (low + high) / 2;
if (nums[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}
return low; // 8
}
}
- 먼저
firstGreaterEqual
메서드를 호출하여 시작 위치를 찾습니다. 이 위치는 주어진target
값보다 크거나 같은 첫 번째 원소의 인덱스입니다. - 만약 시작 위치가
nums
배열의 길이와 동일하거나, 해당 위치의 값이target
와 다르다면, 배열에target
이 존재하지 않으므로 결과 배열[-1, -1]
을 반환합니다. - 시작 위치가 유효하다면, 다시
firstGreaterEqual
메서드를 호출하여 끝 위치를 찾습니다. 이 위치는target
+1보다 크거나 같은 첫 번째 원소의 인덱스에서 1을 뺀 값입니다. 이는target
값의 마지막 위치를 찾는 것을 의미합니다. - 마지막으로, 시작 위치와 끝 위치를 담은 배열
[start, end]
를 생성하여 반환합니다. firstGreaterEqual
메서드는 이진 탐색을 사용하여 주어진 배열nums
에서 주어진target
값 이상인 첫 번째 원소의 인덱스를 찾는 역할을 합니다.- 해당 메서드는 low와 high 두 개의 포인터를 사용하여 이진 탐색을 수행합니다. low는 현재 탐색하는 범위의 왼쪽 경계를 가리키고, high는 현재 탐색하는 범위의 오른쪽 경계 바로 다음을 가리킵니다.
- 반복문을 통해 low가 high보다 작은 동안 탐색을 진행하며, 중간 지점인 mid를 계산합니다. 이후,
nums[mid]
값이target
보다 작다면 탐색 범위를 오른쪽으로 좁히기 위해 low를 mid+1로 업데이트하고, 그렇지 않으면 탐색 범위를 왼쪽으로 좁히기 위해 high를 mid로 업데이트합니다. - 반복문이 종료되면 low 값을 반환합니다. 이는 주어진
target
값보다 크거나 같은 첫 번째 원소의 인덱스를 나타냅니다.
이 알고리즘은 이진 탐색을 사용하므로 firstGreaterEqual
메서드의 시간 복잡도는 O(log n)입니다. 따라서 전체 searchRange 메서드의 런타임 복잡도도 O(log n)입니다. 이를 통해 주어진 문제의 요구사항인 O(log n)의 런타임 복잡도를 만족합니다.
Test
package io.lcalmsky.leetcode.find_first_and_last_position_of_element_in_sorted_array;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class SolutionTest {
@Test
void testAll() {
assertAll(
() -> test(new int[]{5, 7, 7, 8, 8, 10}, 8, new int[]{3, 4}),
() -> test(new int[]{5, 7, 7, 8, 8, 10}, 6, new int[]{-1, -1}),
() -> test(new int[]{}, 0, new int[]{-1, -1})
);
}
private void test(int[] nums, int target, int[] expected) {
// when
Solution solution2 = new Solution();
int[] actual = solution2.searchRange(nums, target);
// then
assertArrayEquals(expected, actual);
}
}