[Leet Code] 4. Median of Two Sorted Arrays
2025. 10. 1. 14:10ㆍCS&알고리즘/Leet Code
https://leetcode.com/problems/median-of-two-sorted-arrays/?envType=problem-list-v2&envId=array&

문제 설명
크기가 각각 m과 n인 두 개의 정렬된 배열 nums1과 nums2가 주어집니다. 두 정렬된 배열의 중앙값(Median)을 반환하세요.
👀 중요
: 전체 실행 시간 복잡도는 O(log(m+n)) 이어야 합니다.
⚠️ O(log(m+n)) 의 문제 풀이는 이진 탐색을 이용하여 풀이해야 한다는것을 인지해야 한다!
문제 풀이
1️⃣ 직관적인 첫번째 풀이 방법 : 배열을 합친 후 정렬하기
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 1. 두 배열을 하나로 합치기
int[] merged = new int[nums1.length + nums2.length];
// 2. 복사
System.arraycopy(nums1, 0, merged, 0, nums1.length);
System.arraycopy(nums2, 0, merged, nums1.length, nums2.length);
// 3. 정렬
Arrays.sort(merged);
// 4. 중앙값 찾기
int n = merged.length;
if (n % 2 == 0) {
return (merged[n/2 - 1] + merged[n/2]) / 2.0;
} else {
return merged[n/2];
}
}
결과 : 요구하는 O(log(m+n)) 보다 훨씬 느림
시간 복잡도: O(m + n) 또는 O((m+n)log(m+n))
- 배열 합치기: O(m + n)
- 정렬하기: O((m+n)log(m+n))
2️⃣ 이진 탐색을 이용한 풀이 방법
Binary Search(이진 탐색)
정렬된 배열에서 특정 값을 찾을 때, 범위를 절반씩 줄여가며 탐색하는 알고리즘
중간 값과 비교해서 왼쪽 또는 오른쪽 범위 중 절반만 탐색하는 방법
정렬이 되어 있어야 크다, 작다를 판단 할 수 있기 때문에 필수적으로 정렬된 배열에서 사용해야한다.
// ✅ 이진 탐색 가능
int[] sorted = {1, 3, 5, 7, 9, 11, 13};
// ❌ 이진 탐색 불가능
int[] unsorted = {5, 1, 9, 3, 7};
선형 탐색과 이진 탐색의 차이
선형 탐색 (Linear Search)
- 시간 복잡도: O(n)
- 최악의 경우: 배열 끝에 있으면 n번 확인
// 처음부터 끝까지 하나씩 확인
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
이진 탐색
- 시간 복잡도: O(log n)
- 최악의 경우: log₂(n)번만 확인
// 중간부터 시작해서 절반씩 제거
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
Binary Search 기본 구조
public int binarySearch(int[] arr, int target) {
int left = 0; // 왼쪽 끝
int right = arr.length - 1; // 오른쪽 끝
while (left <= right) { // 범위가 유효할 때까지
int mid = (left + right) / 2; // 중간 위치
if (arr[mid] == target) {
return mid; // 찾았다!
}
else if (arr[mid] < target) {
left = mid + 1; // 오른쪽 절반 탐색
}
else {
right = mid - 1; // 왼쪽 절반 탐색
}
}
return -1; // 못 찾음
}
배열: [1, 3, 5, 7, 9, 11, 13, 15]
찾는 값: 11
1단계:
[1, 3, 5, 7, 9, 11, 13, 15]
L M R
중간값 7 < 11 → 오른쪽으로!
2단계:
[9, 11, 13, 15]
L M R
중간값 11 == 11 → 찾았다!
이진 탐색을 이용하여 문제 풀어보기
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 1. nums1이 더 짧은 배열이 되도록 보장
// → 이진 탐색 범위를 최소화하기 위함
if (nums1.length > nums2.length) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.length;
int n = nums2.length;
// 2. 이진 탐색 초기 설정
int left = 0;
int right = m;
// 3. Binary Search 시작!
while (left <= right) {
// nums1의 분할 위치
int partition1 = (left + right) / 2;
// nums2의 분할 위치 (왼쪽 그룹 크기를 맞추기 위해)
int partition2 = (m + n + 1) / 2 - partition1;
// 4. 분할선 주변의 값들 구하기
// (경계 처리: 범위를 벗어나면 무한대/무한소 사용)
int maxLeft1 = (partition1 == 0) ?
Integer.MIN_VALUE : nums1[partition1 - 1];
int minRight1 = (partition1 == m) ?
Integer.MAX_VALUE : nums1[partition1];
int maxLeft2 = (partition2 == 0) ?
Integer.MIN_VALUE : nums2[partition2 - 1];
int minRight2 = (partition2 == n) ?
Integer.MAX_VALUE : nums2[partition2];
// 5. 올바른 분할인지 확인
if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
// 중앙값 찾음! 🎉
// 전체 길이가 짝수인 경우
if ((m + n) % 2 == 0) {
return (Math.max(maxLeft1, maxLeft2) +
Math.min(minRight1, minRight2)) / 2.0;
}
// 전체 길이가 홀수인 경우
else {
return Math.max(maxLeft1, maxLeft2);
}
}
// 6. 분할 위치 조정
else if (maxLeft1 > minRight2) {
// nums1의 왼쪽 값이 너무 크다 → 왼쪽으로 이동
right = partition1 - 1;
}
else {
// nums1의 왼쪽 값이 너무 작다 → 오른쪽으로 이동
left = partition1 + 1;
}
}
// 여기까지 오면 안 됨 (문제 조건상 항상 답이 있음)
return 0.0;
}
}
참고
시간 복잡도 비교표
| 시간 복잡도 | 이름 | 예시 | 속도 |
| O(1) | 상수 시간 | 배열의 첫 번째 원소 접근 | 항상 같은 시간 |
| O(log n) | 로그 시간 | 이진 탐색 | 매우 빠름 |
| O(n) | 선형 시간 | 배열 한 번 순회 | 보통 |
| O(n log n) | - | 정렬 (merge sort) | 괜찮음 |
| O(n²) | 제곱 시간 | 이중 for문 | 느림 |
| O(2ⁿ) | 지수 시간 | 모든 부분집합 찾기 | 매우 느림 |
'CS&알고리즘 > Leet Code' 카테고리의 다른 글
| [Leet Code] 876. Middle of the Linked List (1) | 2025.09.01 |
|---|---|
| [Leet Code] 1342. Number of Steps to Reduce a Number to Zero (0) | 2025.09.01 |