TIL
[코테연습] 2560. House Robber IV
크라00
2025. 3. 15. 17:36
https://leetcode.com/problems/house-robber-iv/?envType=daily-question&envId=2025-03-15
1️⃣ 문제 타입
- 이진 검색 (Binary Search on Answer)
- 그리디 알고리즘 (Greedy)
- DP와 유사한 비연속 부분 수열 문제
- 결정 문제 (Decision Problem) 접근 가능
2️⃣ 문제 분석
- nums[] 배열이 주어졌을 때, 비연속적으로 k개의 집을 털 수 있는 최소 capability를 구하는 문제.
- **capability(최대값 제한)**을 조절하면서 k개의 집을 선택해야 함.
- 비연속적인 집만 털 수 있음 → 연속된 집을 선택하면 안 됨.
- 목표는 가장 작은 capability를 찾는 것.
💡 이진 검색(BS)로 답을 찾을 수 있는 이유?
- capability가 작을수록 k개의 집을 털기 어려워짐.
- capability가 크면 쉽게 털 수 있음.
- 즉, capability의 최솟값을 찾기 위해 이진 검색을 활용 가능!
3️⃣ 문제 풀이
✅ Step 1: 이진 검색 범위 설정
- 가능한 capability 값의 최소, 최대를 찾음.
- left = min(nums), right = max(nums) 로 설정.
✅ Step 2: mid 값으로 k개의 집을 털 수 있는지 확인 (isPossible 함수)
- 배열을 탐색하면서 mid 이하의 값만 선택 가능.
- 연속적으로 선택하면 안 되므로, 턴 집 다음 집을 건너뛰어야 함 (i += 2).
- count >= k이면 true, 아니면 false.
✅ Step 3: 이진 검색 진행
- isPossible()이 true라면 더 작은 capability도 가능한지 확인 → right = mid
- false라면 더 큰 capability가 필요 → left = mid + 1
- 결과적으로 left가 최소 capability가 됨.
⏳ 시간 복잡도: O(N log M)
- O(log M): 이진 검색 (M = max(nums) - min(nums))
- O(N): isPossible() 함수 실행
> java
import java.util.Arrays;
class Solution {
// \U0001f3e0 k개의 집을 털 수 있는지 확인하는 함수
private boolean canStealKHouses(int[] nums, int k, int capability) {
int count = 0; // 털 수 있는 집의 개수
int i = 0; // 배열 인덱스
while (i < nums.length) {
if (nums[i] <= capability) { // 현재 집의 돈이 capability 이하이면 털 수 있음
count++;
i += 2; // 비연속적인 집을 털어야 하므로 한 칸 건너뛰기
} else {
i++; // 현재 집을 못 털면 다음 집으로 이동
}
}
return count >= k; // 최소 k개의 집을 털 수 있는지 확인
}
public int minCapability(int[] nums, int k) {
// \U0001f3e0 가능한 최소 및 최대값 설정 (이진 검색 범위)
int left = Arrays.stream(nums).min().getAsInt(); // 배열에서 최솟값 찾기
int right = Arrays.stream(nums).max().getAsInt(); // 배열에서 최댓값 찾기
// \U0001f3af 이진 검색 수행 (최소 최댓값 찾기)
while (left < right) {
int mid = left + (right - left) / 2; // 중간값 계산 (오버플로우 방지)
if (canStealKHouses(nums, k, mid)) {
right = mid; // 더 작은 capability로도 가능할지 확인 (최솟값을 찾기 위해)
} else {
left = mid + 1; // mid 값이 너무 작아 k개의 집을 털 수 없는 경우, 범위를 증가
}
}
return left; // 최소 capability 반환
}
}
>python
class Solution:
def minCapability(self, nums: List[int], k: int) -> int:
left = min(nums)
right = max(nums)
while left < right :
mid = int (left + (right - left) / 2)
if self.isPossible(nums, k, mid) :
right = mid
else :
left = mid + 1
return left
def isPossible(self, nums : List[int], k : int, mid : int) :
cnt = 0
idx = 0
while idx < len(nums) :
if nums[idx] <= mid :
cnt+=1
idx+=2
else :
idx+=1
return cnt >= k