프로그래머스 코딩테스트 Lv.1 문제들
2023-01-20 ~ 01-26
푼 문제 : 나머지 한 점, 나머지 한 점, 두 개 뽑아서 더하기, 2016년, 폰켓몬, 콜라 문제, 크기가 작은 부분 문자열, 소수 찾기, 모의고사
이전에 푼 거 안 올려서 올림.
나머지 한 점
link : https://school.programmers.co.kr/learn/courses/18/lessons/1878
문제 설명
직사각형을 만드는 데 필요한 4개의 점 중 3개의 좌표가 주어질 때, 나머지 한 점의 좌표를 구하려고 합니다. 점 3개의 좌표가 들어있는 배열 v가 매개변수로 주어질 때, 직사각형을 만드는 데 필요한 나머지 한 점의 좌표를 return 하도록 solution 함수를 완성해주세요. 단, 직사각형의 각 변은 x축, y축에 평행하며, 반드시 직사각형을 만들 수 있는 경우만 입력으로 주어집니다.
제한사항
- v는 세 점의 좌표가 들어있는 2차원 배열입니다.
- v의 각 원소는 점의 좌표를 나타내며, 좌표는 [x축 좌표, y축 좌표] 순으로 주어집니다.
- 좌표값은 1 이상 10억 이하의 자연수입니다.
- 직사각형을 만드는 데 필요한 나머지 한 점의 좌표를 [x축 좌표, y축 좌표] 순으로 담아 return 해주세요.
입출력 예
v result
[[1, 4], [3, 4], [3, 10]] | [1, 10] |
[[1, 1], [2, 2], [1, 2]] | [2, 1] |
코드 제출 :
# 제출
def solution(v):
return [v[0][0] ^ v[1][0] ^ v[2][0],v[0][1] ^ v[1][1] ^ v[2][1]]
# 다르게 풀기
def solution(v):
x = [v[0][0],v[1][0],v[2][0]]
y = [v[0][1],v[1][1],v[2][1]]
tmp = [0,0]
for i,j in zip(x,y):
if x.count(i) == 1:
tmp[0] = i
if y.count(j) == 1:
tmp[1] = j
return tmp
해설
^ bitwise XOR 는 배타적 논리합이다. 두 비트 중 하나가 1이면 1이고 나머진 0이다. 예를 들어 1^1 과 0^0은 0이지만 1^0이나 0^1은 1을 반환한다.
A xor A = 0 A xor A xor B = B
같은 값 두 개와 다른 값 한 개를 XOR 하면 다른 값 한 개가 나온다는 원리
v[0][0], v[0][1] : 0001, 0100
v[1][0], v[1][1] : 0011, 0100
v[2][0], v[2][1] : 0011, 1010
# output :
# v1^v3^v5 : 1 -> bin : 0001
# v2^v4^v6 : 10 -> bin : 1010
이건 좀 전에 XOR 관련으로 풀고 나서 이전에 봤던 걸 다시 꺼내본 건데, 결국에는 주어진 v의 원소의 조합 중에서 같은 값 두 개와 다른 값 한 개를 XOR 한다면 다른 값 한 개가 온다는 걸 찾아서 하긴 했지만..
그래서 그냥 아는 대로 다시 풀었음
두 개 뽑아서 더하기
link : https://school.programmers.co.kr/learn/courses/30/lessons/68644
문제 설명
정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요.
제한사항
- numbers의 길이는 2 이상 100 이하입니다.
- numbers의 모든 수는 0 이상 100 이하입니다.
입출력 예
numbers result
[2,1,3,4,1] | [2,3,4,5,6,7] |
[5,0,2,7] | [2,5,7,9,12] |
코드 제출 :
# 제출
from itertools import combinations
def solution(numbers):
return sorted(set(sum(i) for i in list(combinations(numbers,2))))
해설
numbers의 len이 100이하라고 해서 combinations를 쓸 수 있겠다 싶어서 시도. 그리고 중복이 있는 건 나온 경우의 수들의 sum을 set으로 거르고 오름차순으로 반환하라고 해서 sorted를 쓰긴 했는데 다른 사람 풀이들은 대부분 for loop이 이중이라서 이쪽을 좀 더 선호함.
점수 : 1371(+2)
2016년
link : https://school.programmers.co.kr/learn/courses/30/lessons/12901
문제 설명
2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각 SUN,MON,TUE,WED,THU,FRI,SAT
입니다. 예를 들어 a=5, b=24라면 5월 24일은 화요일이므로 문자열 "TUE"를 반환하세요.
제한 조건
- 2016년은 윤년입니다.
- 2016년 a월 b일은 실제로 있는 날입니다. (13월 26일이나 2월 45일같은 날짜는 주어지지 않습니다)
입출력 예
a | b | result |
5 | 24 | "TUE" |
코드 제출 :
# 제출
import datetime
def solution(a, b):
days = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']
return days[datetime.date(2016,a,b).weekday()]
a=5
b=24
solution(a, b)
# 제출2
def solution(m, d):
days = ['SAT','SUN','MON','TUE','WED','THU','FRI']
m = m if m > 2 else 13 if m == 1 else 14
y = (2016-1) if m == 13 or m == 14 else 2016
k = (y%100)
j = int(y/100)
exp = (d+int(13*(m+1)/5)+k+int(k/4)+int(j/4)-(2*j))%7
return days[exp]
해설
이건 사실 import datetime을 알면 끝이긴 하다. MON부터 잡은 이유는 datetime모듈의 weekday가 월요일부터 시작해서 맞춘 것 뿐. 그걸 제외하고는 datetime모듈의 date로 잡고 weekday로 요일에 따른 수를 맞춘 건데, 그걸 제외하고 다른 사람 풀이 중에서는
# 다른 사람 풀이
def soulution(a,b):
months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
days = ['FRI', 'SAT', 'SUN', 'MON', 'TUE', 'WED', 'THU']
return days[(sum(months[:a-1])+b-1)%7]
이게 좀 똑똑했는데 2016년은 윤년이라서 2월이 29일인 걸 제외하고는 1,3,5,7,8,10,12월은 31일까지 2월 제외한 4,6,9,11월은 30일에 끝나는걸 기반으로 하고 거기에서 인덱스로 5월의 날을 맞추고 공식화 한 거.
그러다가 날짜 계산 공식 있는 거 생각나서 추가.
날짜 및 요일 계산에 대해서 생각하다가 정리.
- 일년은 365일이다. 365 = 7일 * 52주 + 1일이다. 따라서 일년의 차이는 같은 월-일이면 요일에 하루 차이가 난다. 예를 들어서 작년 2022년 1월 1일이 토요일이었기 때문에 올해인 2023년 1월 1일은 일요일이다. 거기다가 4년마다 돌아오는 윤년이라는 변수가 숨어있다.
윤년은 7일 * 52주 + 2일이라서 366일이므로 2일의 차이가 난다. 윤년의 규칙은 아래와 같다.
그레고리력의 정확한 윤년 규칙은 다음과 같다.
- 서력 기원 연수가 4로 나누어 떨어지는 해는 윤년으로 한다.(2004년, 2008년, 2012년…)
- 이 중에서 100으로 나누어 떨어지는 해는 평년으로 한다.(2100년, 2200년, 2300년…)
- 그 중에 400으로 나누어 떨어지는 해는 윤년으로 둔다.(1600년, 2000년, 2400년 …) http://ko.wikipedia.org/wiki/윤년
위를 근거로 2016년은 윤년이므로 2월은 29일이다. 그리고 기본적으로 월의 경우 7개월인 1,3,5,7,8,10,12월은 31일이고 2월을 제외한 나머지 4개월 4,6,9,11월은 30일이다. 이를 이용하여 Zeller의 요일계산 공식(Zeller's Congruence 혹은 첼러의 합동식)을 이용하면
![source : https://en.wikipedia.org/wiki/Zeller's_congruence](https://en.wikipedia.org/wiki/Zeller's_congruence)
source : [https://en.wikipedia.org/wiki/Zeller's_congruence](https://en.wikipedia.org/wiki/Zeller's_congruence)
${ h = \left ( q + \left\lfloor {\frac {13(m+1)}{5}}\right\rfloor + K + \left\lfloor {\frac {K}{4}}\right\rfloor + \left\lfloor {\frac {J}{4}}\right\rfloor - 2J \right)\mod 7 }$
- h : 요일 ( 0 = 토, 1 = 일, 2 = 월, ..., 6 = 금 ) → days = ['SAT','SUN','MON','TUE','WED','THU','FRI']
- q : 일 → q
- m : 월 (1월=13, 2=14, 3월=3, 4월=4, … 12월=12) → m = m if m > 2 else 13 if m == 1 else 14
- K : 연도 뒷2자리 ( 연도를 100으로 나 나머지) → (year%100)
- J : 세기 연도 앞 2자리 → int(year/100)
- mod는 나머지 연산을 의미하며, **[ ]**는 가우스 기호로 "X 보다 크지 않은 최대 정수"를 의미하므로 파이썬에서는 int() 캐스팅.
예시 : 2016-05-24 혹은 2016-01-03, 2016-02-11 모두 맞음.
# 제출
def solution(m, d):
days = ['SAT','SUN','MON','TUE','WED','THU','FRI']
m = m if m > 2 else 13 if m == 1 else 14
y = (2016-1) if m == 13 or m == 14 else 2016
k = (y%100)
j = int(y/100)
exp = (d+int(13*(m+1)/5)+k+int(k/4)+int(j/4)-(2*j))%7
return days[exp]
ref : [https://en.wikipedia.org/wiki/Zeller's_congruence](https://en.wikipedia.org/wiki/Zeller's_congruence)
폰켓몬
link : https://school.programmers.co.kr/learn/courses/30/lessons/1845
문제 설명
당신은 폰켓몬을 잡기 위한 오랜 여행 끝에, 홍 박사님의 연구실에 도착했습니다. 홍 박사님은 당신에게 자신의 연구실에 있는 총 N 마리의 폰켓몬 중에서 N/2마리를 가져가도 좋다고 했습니다.홍 박사님 연구실의 폰켓몬은 종류에 따라 번호를 붙여 구분합니다. 따라서 같은 종류의 폰켓몬은 같은 번호를 가지고 있습니다. 예를 들어 연구실에 총 4마리의 폰켓몬이 있고, 각 폰켓몬의 종류 번호가 [3번, 1번, 2번, 3번]이라면 이는 3번 폰켓몬 두 마리, 1번 폰켓몬 한 마리, 2번 폰켓몬 한 마리가 있음을 나타냅니다. 이때, 4마리의 폰켓몬 중 2마리를 고르는 방법은 다음과 같이 6가지가 있습니다.
- 첫 번째(3번), 두 번째(1번) 폰켓몬을 선택
- 첫 번째(3번), 세 번째(2번) 폰켓몬을 선택
- 첫 번째(3번), 네 번째(3번) 폰켓몬을 선택
- 두 번째(1번), 세 번째(2번) 폰켓몬을 선택
- 두 번째(1번), 네 번째(3번) 폰켓몬을 선택
- 세 번째(2번), 네 번째(3번) 폰켓몬을 선택
이때, 첫 번째(3번) 폰켓몬과 네 번째(3번) 폰켓몬을 선택하는 방법은 한 종류(3번 폰켓몬 두 마리)의 폰켓몬만 가질 수 있지만, 다른 방법들은 모두 두 종류의 폰켓몬을 가질 수 있습니다. 따라서 위 예시에서 가질 수 있는 폰켓몬 종류 수의 최댓값은 2가 됩니다.당신은 최대한 다양한 종류의 폰켓몬을 가지길 원하기 때문에, 최대한 많은 종류의 폰켓몬을 포함해서 N/2마리를 선택하려 합니다. N마리 폰켓몬의 종류 번호가 담긴 배열 nums가 매개변수로 주어질 때, N/2마리의 폰켓몬을 선택하는 방법 중, 가장 많은 종류의 폰켓몬을 선택하는 방법을 찾아, 그때의 폰켓몬 종류 번호의 개수를 return 하도록 solution 함수를 완성해주세요.
제한사항
- nums는 폰켓몬의 종류 번호가 담긴 1차원 배열입니다.
- nums의 길이(N)는 1 이상 10,000 이하의 자연수이며, 항상 짝수로 주어집니다.
- 폰켓몬의 종류 번호는 1 이상 200,000 이하의 자연수로 나타냅니다.
- 가장 많은 종류의 폰켓몬을 선택하는 방법이 여러 가지인 경우에도, 선택할 수 있는 폰켓몬 종류 개수의 최댓값 하나만 return 하면 됩니다.
입출력 예
nums | result |
[3,1,2,3] | 2 |
[3,3,3,2,2,4] | 3 |
[3,3,3,2,2,2] | 2 |
코드 제출 :
# 제출
def solution(nums):
n = len(nums)//2
set_num = set(nums)
return len(set_num) if n >= len(set_num) else n
해설
문제는 길지만 결국 이해한 내용으로는
- N/2마리를 선택해야 하며 → 이 수를 넘을 수 없음.
- 최대한 많은 종류의 폰켓몬을 선택한다. → set
이 조건으로 성공했지만 줄일 수 있을 거 같아서 줄여봄.
# short
def solution(nums):
return min(len(set(nums)),len(nums)//2)
그랬더니 다른 사람 풀이도 비슷하더라는..
점수 : 1375(+1)
콜라 문제
link : https://school.programmers.co.kr/learn/courses/30/lessons/132267
문제 설명
오래전 유행했던 콜라 문제가 있습니다. 콜라 문제의 지문은 다음과 같습니다.
정답은 아무에게도 말하지 마세요.
콜라 빈 병 2개를 가져다주면 콜라 1병을 주는 마트가 있다. 빈 병 20개를 가져다주면 몇 병을 받을 수 있는가?
단, 보유 중인 빈 병이 2개 미만이면, 콜라를 받을 수 없다.
문제를 풀던 상빈이는 콜라 문제의 완벽한 해답을 찾았습니다. 상빈이가 푼 방법은 아래 그림과 같습니다. 우선 콜라 빈 병 20병을 가져가서 10병을 받습니다. 받은 10병을 모두 마신 뒤, 가져가서 5병을 받습니다. 5병 중 4병을 모두 마신 뒤 가져가서 2병을 받고, 또 2병을 모두 마신 뒤 가져가서 1병을 받습니다. 받은 1병과 5병을 받았을 때 남은 1병을 모두 마신 뒤 가져가면 1병을 또 받을 수 있습니다. 이 경우 상빈이는 총 10 + 5 + 2 + 1 + 1 = 19병의 콜라를 받을 수 있습니다.
문제를 열심히 풀던 상빈이는 일반화된 콜라 문제를 생각했습니다. 이 문제는 빈 병 a개를 가져다주면 콜라 b병을 주는 마트가 있을 때, 빈 병 n개를 가져다주면 몇 병을 받을 수 있는지 계산하는 문제입니다. 기존 콜라 문제와 마찬가지로, 보유 중인 빈 병이 a개 미만이면, 추가적으로 빈 병을 받을 순 없습니다. 상빈이는 열심히 고심했지만, 일반화된 콜라 문제의 답을 찾을 수 없었습니다. 상빈이를 도와, 일반화된 콜라 문제를 해결하는 프로그램을 만들어 주세요.
콜라를 받기 위해 마트에 주어야 하는 병 수 a, 빈 병 a개를 가져다 주면 마트가 주는 콜라 병 수 b, 상빈이가 가지고 있는 빈 병의 개수 n이 매개변수로 주어집니다. 상빈이가 받을 수 있는 콜라의 병 수를 return 하도록 solution 함수를 작성해주세요.
제한사항
- 1 ≤ b < a ≤ n ≤ 1,000,000
- 정답은 항상 int 범위를 넘지 않게 주어집니다.
입출력 예
a | b | n | result |
2 | 1 | 20 | 19 |
3 | 1 | 20 | 9 |
코드 제출 :
# 제출
def solution(a, b, n):
answer=0
while n >= a:
answer += (n//a)*b
n = (n//a)*b+(n%a)
return answer
해설
처음에는 b로서 받는 걸 제대로 생각 못하고 그리고 나머지를 다시 계산하는 과정을 잘못해서 아래 처럼 제출하고 거진 다 틀림.
def solution(a, b, n):
answer=0
while n > a:
answer += n//a
n = (n%a)*b+(n//a)
return answer+n//a
그러고 나서 뭐지 하면서 다시 보다가 n이 a와 같으면 다시 나눠야 하니까 n ≥ a 처리부터 시작하고 n을 a로 나눈 몫에 b를 곱하고 다시 얻고 나머지를 더해서 n에 덧씌우고 answer에도 b만큼 얻은 걸 적용.
점수 : 1379(+4)
크기가 작은 부분 문자열
link : https://school.programmers.co.kr/learn/courses/30/lessons/147355
문제 설명
숫자로 이루어진 문자열 t와 p가 주어질 때, t에서 p와 길이가 같은 부분문자열 중에서, 이 부분문자열이 나타내는 수가 p가 나타내는 수보다 작거나 같은 것이 나오는 횟수를 return하는 함수 solution을 완성하세요.
예를 들어, t="3141592"이고 p="271" 인 경우, t의 길이가 3인 부분 문자열은 314, 141, 415, 159, 592입니다. 이 문자열이 나타내는 수 중 271보다 작거나 같은 수는 141, 159 2개 입니다.
제한사항
- 1 ≤ p의 길이 ≤ 18
- p의 길이 ≤ t의 길이 ≤ 10,000
- t와 p는 숫자로만 이루어진 문자열이며, 0으로 시작하지 않습니다.
입출력 예
t | p | result |
"3141592" | "271" | 2 |
"500220839878" | "7" | 8 |
"10203" | "15" | 3 |
코드 제출 :
# 제출
def solution(t, p):
len_p = len(p)
tmp = [int(t[i:i+len_p]) for i in range(len(t)) if len(t[i:i+len_p]) == len_p]
return sum(1 for num in tmp if int(p) >= num)# 제출
# short
def solution(t, p):
len_p = len(p)
return len([int(t[i:i+len_p]) for i in range(len(t)) if len(t[i:i+len_p]) == len_p and int(t[i:i+len_p]) <= int(p)])
해설
slicing을 이용해서 했는데 short으로도 줄여봄. 그런데 실제 제출해보면 먼저 제출한 게 더 시간복잡도가 낮음… 흠?
점수 : 1380(+1)
소수 찾기
link : https://school.programmers.co.kr/learn/courses/30/lessons/12921
문제 설명
1부터 입력받은 숫자 n 사이에 있는 소수의 개수를 반환하는 함수, solution을 만들어 보세요.
소수는 1과 자기 자신으로만 나누어지는 수를 의미합니다.(1은 소수가 아닙니다.)
제한 조건
- n은 2이상 1000000이하의 자연수입니다.
입출력 예
n | result |
10 | 4 |
5 | 3 |
코드 제출 :
# 제출
def prime(x):
for d in range(2,int(x**.5)+1):
if x%d==0:
return False
return True
def solution(n):
return len([i for i in range(2,n+1) if prime(i)])
해설
이전에 소수를 찾는 함수를 만든 걸 응용해서 썼는데, 에라토스테네스의 체를 더 간결하게 구현한 걸 봄
def solution(n):
num=set(range(2,n+1))
for i in range(2,n+1):
if i in num:
num-=set(range(2*i,n+1,i))
return len(num)
이것도 꽤 똑똑하게 잘 짠 듯 물론 일정 이상 가면 나중에 같은 반복이겠지만 어차피 소수 찾는 건 한 번 다 돌려야 하는 상황이고..
점수 : 1385(+5)
모의고사
link : https://www.notion.so/877a045b10c14b309c7e63c8dd472158
문제 설명
수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.
1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...
1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.
제한 조건
- 시험은 최대 10,000 문제로 구성되어있습니다.
- 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
- 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.
입출력 예
answers | return |
[1,2,3,4,5] | [1] |
[1,3,2,4,2] | [1,2,3] |
코드 제출 :
# 제출
def solution(answers):
N = len(answers)
one = ([1, 2, 3, 4, 5]*N)[:N]
two = ([2, 1, 2, 3, 2, 4, 2, 5]*N)[:N]
three = ([3, 3, 1, 1, 2, 2, 4, 4, 5, 5]*N)[:N]
count1, count2, count3 = 0,0,0
for i in range(N):
if answers[i] == one[i]:
count1 += 1
if answers[i] == two[i]:
count2 += 1
if answers[i] == three[i]:
count3 += 1
score = [count1, count2, count3]
max_mem = max(score)
return sorted(i+1 for i in range(3) if max_mem == score[i])
해설
이건 처음에 문제 구현 부터 좀 버벅대다가 그냥 해보자 싶어서 1,2,3번을 각자 만들고 문제 맞춘 거 카운트 하려고 count1~3까지 만들고 for문으로 맞으면 count를 하나하나 시키고 socre에서 가장 큰 애 하나 잡아놓고 동일 수 있으면 index에서 +1하고 sorted했는데 처음에는 [1, 2, 3, 4, 5] 이렇게만 했더니 런타임 에러길래 체크하니까 문제의 길이를 파악을 안 했더란.. 그래서 문제 길이만큼 늘리게 해놓고 slicing함.
하고 나서 좀 줄여본 게 아래와 같고
def solution(answers):
N = len(answers)
one = ([1, 2, 3, 4, 5]*N)[:N]
two = ([2, 1, 2, 3, 2, 4, 2, 5]*N)[:N]
three = ([3, 3, 1, 1, 2, 2, 4, 4, 5, 5]*N)[:N]
score = [0,0,0]
for i in range(N):
if answers[i] == one[i]:
score[0] += 1
if answers[i] == two[i]:
score[1] += 1
if answers[i] == three[i]:
score[2] += 1
max_mem = max(score)
return sorted(i+1 for i in range(3) if max_mem == score[i])
여기서 더 못 줄일 거 같아서 다른 사람 풀이 봤는데 결국 비슷했다…
점수 : 1388(+3)
'스터디 > Python' 카테고리의 다른 글
[CodingTest][2023-04-20~]프로그래머스 코딩테스트 Lv.1 문제들 - fin (2) | 2023.05.02 |
---|---|
[CodingTest][2023-02-14~]프로그래머스 코딩테스트 Lv.1 문제들 (1) | 2023.04.10 |
[CodingTest][2023-01-13~01-20]프로그래머스 코딩테스트 Lv.1 (1) | 2023.01.20 |
[CodingTest][2023-01-11~13]프로그래머스 코딩테스트 Lv.1 문제들 (1) | 2023.01.13 |
[CodingTest][2023-01-02~2022-01-10]프로그래머스 코딩테스트 Lv.0 문제들 - fin (0) | 2023.01.10 |