| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- amazon ecs
- ssh
- AWS 비용 절감
- PostgreSQL
- 회고
- Go-lang
- 청첩장 모임
- 오블완
- study
- leetcode
- Playwright
- docker
- 논문 정리
- 지표
- 경로 계획 알고리즘
- 디자인 패턴
- 신혼 여행
- 커머스
- terraform
- github
- 생성 패턴
- 실용주의 프로그래머
- MAPF
- 구조 패턴
- 티스토리챌린지
- 14일 공부
- Rust
- Til
- DevOps
- AWS
- Today
- Total
밤 늦게까지 여는 카페
[leetcode] 2516. Take K of Each Character From Left and Right 본문
안녕하세요. 오늘은 leetcode의 2516. Take K of Each Character From Left and Right 문제를 풀어봤습니다.
1. 문제
이 문제에서는 "a", "b", "c"로만 이뤄진 문자열과 숫자 k가 주어집니다.
한번에 왼쪽 끝 혹은 오른쪽 끝에 있는 문자를 하나씩 잘라낼 수 있을 때, "a", "b", "c"를 각각 최소 k개 씩 뽑을 수 있는 최소한의 횟수를 구해야 합니다.
- 만약 주어진 문자열이 조건을 만족하지 않는다면 -1을 반환합니다.
예시)
- "abcccba", k=2
- 왼쪽에서 3개 오른쪽에서 3개, 총 6번 자르는 자르는 것이 최소한의 횟수입니다.

2. 풀이
2.1. brute force
역시 가장 간단한 방법은 모든 경우의 수를 전부 따져보는 것입니다.
이 문제는 어떻게 모든 경우의 수를 찾을 수 있을까요? 생각보다 단순합니다.
n에 3 * k부터 문자열의 길이까지 대입하면서 다음 과정을 반복하면 됩니다.
- "a", "b", "c"가 각각 최소 k개씩은 존재해야 하므로 최소한 3 * k 번은 잘라야 하니 3 * k부터 시작합니다.
1. 문자열을 왼쪽에서 n개, 오른쪽에서 0개 자르고 "a", "b", "c"가 최소 k개씩 존재하는지 확인합니다.
2. 문자열을 왼쪽에서 n-1개, 오른쪽에서 1개 자르고 "a", "b", "c"가 최소 k개씩 존재하는지 확인합니다.
...
n. 문자열을 왼쪽에서 0개, 오른쪽에서 n개 자르고 "a", "b", "c"가 최소 k개씩 존재하는지 확인합니다.
하지만 이 방법의 시간복잡도는 O(n^2)으로 문자열의 길이가 최대 10^5까지 늘어날 수 있는 이 문제에서는 사용할 수 없습니다.
2.2. binary search
저에게 brute force 다음으로 만만한 방법이 binary search인 것 같습니다.
binary search를 적용하는 방법은 간단했습니다.
3 * k 부터 문자열의 길이까지 점진적으로 증가시키는 대신 3 * k와 문자열의 길이 사이에서 이진 탐색을 진행하는 것이죠.
- mid 횟수가 조건을 만족했을 때는 3 * k와 mid 사이에서 찾기

- mid 횟수가 조건을 만족하지 않을 때는 mid와 문자열의 길이에서 찾기

이렇게 이진 탐색으로 문제를 풀 수 있었습니다.
하지만 runtime 효율성이 극악입니다... 다음에는 이걸 개선해봐야겠습니다!

+ 코드
class Solution:
def takeCharacters(self, s: str, k: int) -> int:
if k == 0:
return 0
if k > len(s) // 3:
return -1
min_length = float("inf")
l = 3 * k
r = len(s)
while l <= r:
mid = (l + r) // 2
result = get_min_minutes(s, mid, k)
if result:
r = mid - 1
min_length = min(min_length, mid)
else:
l = mid + 1
return min_length if min_length != float("inf") else -1
def get_min_minutes(s, length, k):
result = [0] * 3
for c in s[:length]:
result[ord(c) - ord("a")] += 1
if check_enough(result, k):
return True
for right_num in range(1, length+1):
result[ord(s[length-right_num]) - ord("a")] -= 1
result[ord(s[-right_num]) - ord("a")] += 1
if check_enough(result, k):
return True
return False
def check_enough(result, k):
for r in result:
if r < k:
return False
return True
'알고리즘 > 문제풀이' 카테고리의 다른 글
| [leetcode] 2257. Count Unguarded Cells in the Grid (1) | 2024.11.23 |
|---|---|
| [leetcode] 2516. Take K of Each Character From Left and Right #2 (0) | 2024.11.22 |
| [leetcode] 1652. Defuse the Bomb (2) | 2024.11.19 |
| [leetcode] 2563. Count the Number of Fair Pairs #2 (0) | 2024.11.17 |
| [leetcode] 2563. Count the Number of Fair Pairs (3) | 2024.11.15 |