👉 사용 언어 : PYTHON3
신규 아이디 추천
✅ Solution
def solution(new_id):
s_ch = '~!@#$%^&*()=+[{]}:?,<>/'
ans = list(new_id.lower())
for i in ans:
if i in s_ch:
ans[ans.index(i)] = ' '
ans = [ch for ch in ans if ch != ' ']
for i in range(len(ans)-1):
if ans[i] == '.' and ans[i+1] == '.':
ans[i] = ' '
str_ans = (''.join(ans)).replace(' ', '')
for j in range(len(str_ans)):
if str_ans[j] == '.':
str_ans = str_ans.replace('.', ' ', 1)
else:
break
str_ans = str_ans.replace(' ', '')
if len(str_ans) == 0:
str_ans += 'a'
str_ans = str_ans[0:15]
for j in range(len(str_ans)-1, -1, -1):
if str_ans[j] != '.':
str_ans = str_ans[0:j+1]
break
if len(str_ans) <= 2:
str_ans += (str_ans[len(str_ans)-1]*(3-len(str_ans)))
return str_ans
👉 아이디어
- 확인 단계별로 코드 작성
- 고려해야할 경우의 수가 너무 많아져서 코드가 너무 더러워짐 ..
- 정규표현식 사용하는 방향으로 다시 생각하기 ( 아래 다른 사람 풀이 참고해서 )
👉 문자열에서 .index( ) 를 사용하여 해당 값의 인덱스를 추출할 때, 중복 되는 값이 있으면 맨 처음 에 오는 값의 인덱스를 리턴한다.
따라서, '...a'에서 .index('.') 를 하면 몇 번을 추출해도 0만 나온다.
👉 .startwith( ) 및 .endwith( ) : ~로 시작하는지? ~로 끝나는지? 판단
✅ 다른 사람 풀이 참고
import re
def solution(new_id):
st = new_id
st = st.lower()
st = re.sub('[^a-z0-9\-_.]', '', st)
st = re.sub('\.+', '.', st)
st = re.sub('^[.]|[.]$', '', st)
st = 'a' if len(st) == 0 else st[:15]
st = re.sub('^[.]|[.]$', '', st)
st = st if len(st) > 2 else st + "".join([st[-1] for i in range(3-len(st))])
return st
👉 정규표현식을 사용하려면 "re" 모듈 사용
👉 re.sub('[^a-z0-9\-_.]', '', st) : 소문자(a-z) 또는 숫자(0-9) 또는 (-_.)가 아닌 문자 제거 (''로)
👉 re.sub('\.+', '.', st) : '.' 이 여러 개 있으면 '.' 하나로 변환 (+ : + 앞에 있는 문자가 최소 한 번 이상 반복되어야 매치)
👉 re.sub('^[.]|[.]$', '', st) : '.'이 처음 또는 끝에 있으면 제거 (''로)
++ 빈 문자열일 경우 'a' 추가하는 조건과 문자열이 16자 이상일 경우 15자까지만 슬라이싱하는 조건을 동시에 구현 ++
🔗 정규표현식 참고 사이트 : https://nachwon.github.io/regular-expressions/
[Python 문법] 정규표현식 (Regular Expressions)
정규표현식에 대해 알아보고 Python으로 정규표현식을 사용하는 방법에 대해 알아본다.
nachwon.github.io
로또의 최고 순위와 최저 순위
✅ Solution
def rank(score):
if score > 1:
return 7-score
else:
return 6
def solution(lottos, win_nums):
answer = 0
cnt_0 = lottos.count(0)
for i in lottos:
if i in win_nums:
answer += 1
return [rank(answer+cnt_0), rank(answer)]
👉 아이디어
- lottos 배열을 반복문을 돌려 순회한다.
- 원소 in win_nums 해서 true 이면 카운트한다.
- .count( ) 사용하여 0의 개수를 카운트한다.
- min : true일때 카운트한 값 , max : min + 0일때 카운트한 값
- 등수 = 7-점수 (대칭)이며 점수가 0, 1일때 모두 6등이 된다는 것만 예외 로 처리해주면된다.
- 점수 > 1 : 7-점수(=등수) 리턴
- 점수 <= 1 : 6 (=등수) 리턴
- [max 등수 , min 등수]를 리턴한다.
✅ 다른 사람 풀이 참고
def solution(lottos, win_nums):
rank=[6,6,5,4,3,2,1]
cnt_0 = lottos.count(0)
ans = 0
for x in win_nums:
if x in lottos:
ans += 1
return rank[cnt_0 + ans],rank[ans]
👉 비슷한 아이디어인데 아예 인덱스(=점수)와 원소(=등수)를 사용하여 더 깔끔하게 풀이하였다.
👉 []로 따로 안묶어주고 그냥 값을 2개 이상 리턴하면 자동으로 리스트로 묶어준다 !!
개인정보 수집 유효기간
✅ Solution
from datetime import datetime
def solution(today, terms, privacies):
ans = []
term_exp = {}
exp_date = []
today_date = datetime.strptime(today, "%Y.%m.%d")
for i in terms:
term_exp[i.split()[0]] = i.split()[1]
for j in privacies:
date = j.split()[0]
month = int(date.split('.')[1]) + int(term_exp[j.split()[1]])
year = int(date.split('.')[0])
if month <= 12:
exp_date.append(date.split('.')[0]+'.'+str(month)+'.'+date.split('.')[2])
elif month > 12 and month % 12 != 0:
exp_date.append(str(year+month//12)+'.'+str(month-12*(month//12))+'.'+date.split('.')[2])
else:
exp_date.append(str(year+(month//12-1))+'.'+'12'+'.'+date.split('.')[2])
for k in exp_date:
k_date = datetime.strptime(k, "%Y.%m.%d")
if k_date <= today_date:
ans.append(exp_date.index(k)+1)
exp_date[exp_date.index(k)] = ''
return ans
👉 아이디어
- "약관-유효기간" 딕셔너리 생성 (term_exp) _ 약관 종류 중복되지 않으므로 key로 사용 가능함
- "파기 날짜" 배열 생성 (exp_date)
- 약관 유효기간 + 현재 달 통해 파기 날짜 구할 때, 달이 12로 나누어떨어지는 경우 처리 필요 _ 0이 될 수 있음
- 약관 유효기간 + 현재 달 <= 12인 경우
- 약관 유효기간 + 현재 달 > 12이면서 12의 배수가 아닌 경우
- 약관 유효기간 + 현재 달 > 12이면서 12의 배수인 경우 ✔️
- today 날짜와 exp_date의 각 날짜를 비교하여 후자가 더 작거나 같은 경우 정답 배열에 인덱스+1 추가
- .index( ) 사용할때는 무조건 중복 원소에서 실패 원인이 있을 경우가 대부분! ( 맨 처음 원소 인덱스만 리턴하므로 )
- 해당 풀이에서는 정답 배열에 추가한 값은 ''로 초기화시켜 중복 문제를 해결하였다.
✅ 다른 사람 풀이 참고
def to_days(date):
year, month, day = map(int, date.split("."))
return year * 28 * 12 + month * 28 + day
def solution(today, terms, privacies):
months = {v[0]: int(v[2:]) * 28 for v in terms}
today = to_days(today)
expire = [
i + 1 for i, privacy in enumerate(privacies)
if to_days(privacy[:-2]) + months[privacy[-1]] <= today
]
return expire
👉 "map"을 사용하여 년도 / 월 / 일 3가지 변수에 한번에 저장
👉 날짜를 문자열 or datetime 형식으로 비교하지 않고 년/월을 모두 *28 하여 day로 변환 하여 그 값(정수)끼리 비교하였다.
👉 months : "약관-유효기간" 딕셔너리
👉 "enumerate" 사용하여 privacy 정보("개인정보 수집 일자 및 약관 종류")와 순서 정보(index+1)을 동시에 접근 가능하도록 하였다.
둘만의 암호
✅ Solution
def solution(s, skip, index):
answer = ''
for i in s:
cnt = 1
base = ord(i) + cnt
while cnt <= index:
if base > ord('z'):
base -= 26
if chr(base) not in skip:
cnt += 1
base += 1
answer += chr(base-1)
return answer
👉 아이디어
- s 에 각각 index 만큼 더한 문자를 다시 저장
- 아스키코드 사용 ( "a" = 97 ~ "z" = 122 )
- 문자 > 아스키코드 변환 : ord()
- 이 과정에서 skip 에 있는 문자는 제외해야 함
s 의 원소중 skip 에 있는 문자가 존재하면 해당 원소 + (index-s의 원래 문자)
👉 문자열.find("특정 문자")
: 문자열 내 특정 문자 찾는 함수
: 있으면 해당 문자의 index를, 없으면 -1을 리턴한다.
👉 특정 문자 in 문자열
: 문자열 내 특정 문자 찾는 함수
: 있으면 true를, 없으면 false를 리턴한다.
: 반대 _ 특정 문자 not in 문자열
✅ 다른 사람 풀이 참고
from string import ascii_lowercase
def solution(s, skip, index):
result = ''
a_to_z = set(ascii_lowercase)
a_to_z -= set(skip)
a_to_z = sorted(a_to_z)
l = len(a_to_z)
dic_alpha = {alpha:idx for idx, alpha in enumerate(a_to_z)}
for i in s:
result += a_to_z[(dic_alpha[i] + index) % l]
return result
햄버거 만들기
✅ Solution
def solution(ingredient):
answer = ''.join(map(str, ingredient))
while "1231" in answer:
answer = answer.replace("1231", "", 1)
return (len(ingredient) - len(answer)) // 4
👉 주의 _ "1231"을 한번에 여러 개 제거할 수 없다.
( 그래서 위의 코드처럼 answer.replace("1231", "", 1)을 썼더니 시간 초과 )
👉 replace 를 쓰면 결국 문자열의 전체 길이를 탐색 + @ 해서 시간복잡도가 꽤 걸린다.
def solution(ingredient):
i = 0
ans = 0
while i < len(ingredient)-3:
if ingredient[i:i+4] == [1, 2, 3, 1]:
del ingredient[i:i+4]
ans += 1
if i < 4:
i = 0
else:
i -= 3
else:
i += 1
return ans
👉 [1, 2, 3, 1]을 del을 사용하여 지운 후, 두 개의 케이스로 나눠 i를 초기화한다.
- i가 4보다 작을 경우 : 아예 0으로 초기화
- i가 4보다 크거나 같을 경우 : 지운 값은 [i] ~ [i+3]이므로 다시 [1, 2, 3, 1]이 나올 수 있는 범위는 i-3부터이므로 i-3으로 초기화
- 이렇게 나눠서 값을 초기화하면 시간초과를 방지할 수 있다.
👉 아이디어
- 정수배열 ingredient를 문자열로 만들기
- ''.join(map(str, ingredient))
- 해당 문자열에서 "1231"이 없을때까지 반복문 돌려서
.replace("1234", "")하기 - (원래 ingredient 길이 - 남은 문자열 길이) // 4 를 리턴한다.
👉 리스트(변형 객체) 복사
- 리스트1 = 리스트2 : C 언어에서 포인터만 지정한 것과 비슷한 경우 (list는 1개만 존재하지만 2가지 이름으로 가리키는 것)
- 리스트1을 수정하면 리스트2에도 반영되고, 리스트2를 수정하면 리스트1에도 반영되는 이슈 발생
- shallow copy(얕은 복사 ) : 하나의 리스트를 수정해도 다른 하나가 바뀌지 않는다.
- 리스트1 = 리스트2.copy()
- 리스트1 = 리스트2[ : ]
✅ 다른 사람 풀이 참고
def solution(ingredient):
s = []
cnt = 0
for i in ingredient:
s.append(i)
if s[-4:] == [1, 2, 3, 1]:
cnt += 1
for i in range(4):
s.pop()
return cnt
👉 시간복잡도가 훨씬 적음
👉 새로운 배열에 값을 하나씩 넣고 해당 배열에서 [1, 2, 3, 1]이 존재하면 카운트+1
( 그리고나서 새로운 배열에서 [1, 2, 3, 1]을 pop( ) 한다. )
'알고리즘풀이 > 프로그래머스' 카테고리의 다른 글
| [1/25] Kakao Internship 기출문제 풀이 (0) | 2024.01.18 |
|---|---|
| [1/18] Kakao Internship 기출문제 풀이 (0) | 2024.01.11 |
| [성격 유형 검사하기] (2) | 2023.11.28 |
| [11/22] Lv1. (2) | 2023.11.18 |
| [11/16] Lv1. (0) | 2023.11.10 |