1. 문제: https://school.programmers.co.kr/learn/courses/30/lessons/17686
- 먼저, 배열 sort시 커스텀하게 비교해야하므로 cmp_to_key 라이브러리를 사용했고, 비교하는 함수인 compare 함수를 작성했다.
- 정렬의 조건을 정리하자면 다음과 같다.
1) HEAD: 문자로 이루어져있으며, 반드시 한글자 이상이다. 파일명은 HEAD 기준으로 사전순으로 정렬하며, 대소문자를 구분하지 않는다.
2) NUMBER: 최소 한글자 이상의 연속된 숫자로 이루어져 있으며, 숫자 순으로 정렬한다.
3) TAIL: HEAD와 NUMBER 외의 나머지 부분으로, 이부분은 정렬에 영향을 주지 않는다.
❌ 틀린 풀이
from functools import cmp_to_key
def compare(a, b):
axis = 1 # 1이면 뒤, 0이면 그대로, -1이면 앞
head_end_index = 0
number_end_index = 0
for i in range(len(a)):
if a[i].isdigit():
head_end_index = i # 숫자가 시작되는 첫 인덱스여야하므로 인덱스를 찾고 break한다.
break
for i in range(head_end_index, len(a)):
if not a[i].isdigit(): # 위 head_end_index에서부터 숫자가 아니게 되는 첫 지점을 찾게 되면, 그 사이가 숫자가 된다.
number_end_index = i
break
else:
number_end_index = len(a)
a_header = a[:head_end_index]
b_header = b[:head_end_index]
a_number = a[head_end_index:number_end_index]
b_number = b[head_end_index:number_end_index]
if a_header.lower() > b_header.lower():
axis = 1
elif a_header.lower() < b_header.lower():
axis = -1
else:
if int(a_number) > int(b_number):
axis = 1
elif int(a_number) < int(b_number):
axis = -1
else:
axis = 0
return axis
def solution(files):
return sorted(files, key=cmp_to_key(compare))
해당 코드의 문제는 다음과 같다.
1) HEAD와 NUMBER, TAIL을 분리하는 기준을 무조건 a로 둔점
--> a와 b의 HEAD, NUMBER, TAIL 을 분리하는 인덱스는 서로 다를 수 있다.
ex) "F-5 Freedom" 과 "B-50 Superfortress"에서 HEAD는 각각 F-, B- / NUMBER는 5와 50으로, NUMBER와 TAIL을 구분하는 인덱스는 서로 다르다.
--> 따라서 a와 b를 각각 HEAD, NUMBER, TAIL로 분리 후 판단해야한다.
2)
number_end_index = 0
for i in range(head_end_index, len(a)):
if not a[i].isdigit(): # 위 head_end_index에서부터 숫자가 아니게 되는 첫 지점을 찾게 되면, 그 사이가 숫자가 된다.
number_end_index = i
break
해당 코드는 TAIL의 "아무 글자도 없을 수도 있다" 라는 조건을 무시한 것이다.
즉, 예를들어 파일명이 "F-15"일 경우 HEAD는 F-, NUMBER는 15, TAIL은 빈 문자열이므로 이 경우에 number_end_index가 0이 되어 하단에 header, number를 분리하는 변수에서 런타임 오류가 발생하게 된다.
--> 따라서 number_end_index를 file의 끝 인덱스로 둔 다음 반복문을 실행함으로써 TAIL이 빈 문자열일 경우를 커버한다.
✅ 수정한 풀이
from functools import cmp_to_key
def compare(a, b):
axis = 0 # 1이면 뒤, 0이면 그대로, -1이면 앞으로 정렬하기 이므로, 해당 값을 반환하기 위한 축
def extract_from_file(file): # 함수를 별도로 생성하여 a, b 따로 분리해서 비교하도록 함
# 1) HEAD 분리 작업
head_end_index = 1 # 최소한 1글자 이상이므로 초기값 1
for i in range(len(file)):
if file[i].isdigit():
head_end_index = i
break
# 2) NUMBER 분리 작업
number_end_index = len(file) # 위 틀린 코드에서 수정한 부분
for i in range(head_end_index, len(file)):
if not file[i].isdigit(): # number가 시작하는 지점부터 끝까지의 범위에서 처음으로 숫자가 아닌 수가 나타나는 구간이 number임
number_end_index = i
break
return file[:head_end_index], file[head_end_index:number_end_index]
a_header, a_number = extract_from_file(a)
b_header, b_number = extract_from_file(b)
# 대소문자 구분 없음 --> 소문자화한 다음에 비교
# 사전순 정렬
if a_header.lower() > b_header.lower():
axis = 1
elif a_header.lower() < b_header.lower():
axis = -1
else: # 만약에 HEAD가 서로 같다면, NUMBER를 숫자 순으로 정렬
if int(a_number) > int(b_number):
axis = 1
elif int(a_number) < int(b_number):
axis = -1
else: # HEAD와 NUMBER도 서로 같다면, 주어진 순서를 유지 --> 0
axis = 0
return axis
def solution(files):
return sorted(files, key=cmp_to_key(compare))
2. 문제: https://school.programmers.co.kr/learn/courses/30/lessons/42747
- 나는 문제 설명보고 야생(?)으로 풀었는데, 카테고리가 정렬이다 ..!!!
✅ 나의 풀이
def solution(citations):
answer = 0 #h
cited = 0
notcited = 0
arr = []
while answer <= max(citations): # 0부터 인용의 최대횟수까지 차례대로 비교함
cited = 0
notcited = 0
for i in citations:
if i>=answer:
cited += 1
if i<=answer:
notcited += 1
if cited>=answer and notcited<=answer:
arr.append(answer)
answer += 1
return max(arr) if len(arr) else 0
✅ 다른 사람 풀이
def solution(citations):
citations = sorted(citations)
l = len(citations)
for i in range(l):
if citations[i] >= l-i:
return l-i
return 0
- 첫번째 입출력에 대해 정렬하게 되면 [0, 1, 3, 5, 6] 이다. 이에 대해 따져보면
0: 0번 이상 인용된 논문이 5편 이상, 나머지 논문 1번 이하 인용 ❌
1: 1번 이상 인용된 논문이 4편 이상, 나머지 논문 2번 이하 인용 ❌
3: 3번 이상 인용된 논문이 3편 이상, 나머지 논문 3번 이하 인용 ✅
5: 5번 이상 인용된 논문이 2편 이상, 나머지 논문 4번 이하 인용 ❌
6: 6번 이상 인용된 논문이 1편 이상, 나머지 논문 5번 이하 인용 ❌
- citations[i]: 논문이 인용된 최소 횟수, len - i: citations[i]번 이상 인용된 논문의 갯수
오늘 알게 된 점
1. 문자열 관련 python 함수 다시 정리! 꼭 기억하자
isdigit() : 해당 character가 정수인지에 대한 bool 값
isalpha() : 해당 character가 알파벳 문자인지에 대한 bool 값 (특수문자의 경우 알파벳이 아니기때문에 False 반환함)
isupper() : 해당 character가 대문자인지에 대한 bool 값
islower() : 해당 character가 소문자인지에 대한 bool 값
문자열 전체 대문자로 치환하여 문자열 반환 : upper()
문자열 전체 소문자로 치환하여 문자열 반환 : lower()
문자열 처음 대문자로 시작하도록 변환하여 문자열 반환 : capitalize()
문자열 전체 소<->대문자로 치환하여 문자열 반환 : swapcase()
'⚙️ 알고리즘 > 문제풀이' 카테고리의 다른 글
[Swift] 프로그래머스 JadenCase 문자열 만들기 (0) | 2025.05.09 |
---|---|
[Swift] 백준 1913, 프로그래머스 베스트앨범 (0) | 2025.05.07 |
[Python] 프로그래머스 가장 큰 수 (0) | 2025.05.05 |
[Python] 백준 9963(N-Queen) (0) | 2025.05.02 |
[Python] 백준 2239, 프로그래머스 피로도 (0) | 2025.05.01 |