본문 바로가기
스터디/Python

[CodingTest][2023-01-20~26]프로그래머스 코딩테스트 Lv.1 문제들

by SeO.V 2023. 2. 14.

프로그래머스 코딩테스트 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일같은 날짜는 주어지지 않습니다)

입출력 예

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월의 날을 맞추고 공식화 한 거.

그러다가 날짜 계산 공식 있는 거 생각나서 추가.

 

 

날짜 및 요일 계산에 대해서 생각하다가 정리.

  1. 일년은 365일이다. 365 = 7일 * 52주 + 1일이다. 따라서 일년의 차이는 같은 월-일이면 요일에 하루 차이가 난다. 예를 들어서 작년 2022년 1월 1일이 토요일이었기 때문에 올해인 2023년 1월 1일은 일요일이다. 거기다가 4년마다 돌아오는 윤년이라는 변수가 숨어있다.

윤년은 7일 * 52주 + 2일이라서 366일이므로 2일의 차이가 난다. 윤년의 규칙은 아래와 같다.

그레고리력의 정확한 윤년 규칙은 다음과 같다.

  1. 서력 기원 연수가 4로 나누어 떨어지는 해는 윤년으로 한다.(2004년, 2008년, 2012년…)
  2. 이 중에서 100으로 나누어 떨어지는 해는 평년으로 한다.(2100년, 2200년, 2300년…)
  3. 그 중에 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가지가 있습니다.

  1. 첫 번째(3번), 두 번째(1번) 폰켓몬을 선택
  2. 첫 번째(3번), 세 번째(2번) 폰켓몬을 선택
  3. 첫 번째(3번), 네 번째(3번) 폰켓몬을 선택
  4. 두 번째(1번), 세 번째(2번) 폰켓몬을 선택
  5. 두 번째(1번), 네 번째(3번) 폰켓몬을 선택
  6. 세 번째(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

 

해설

더보기

문제는 길지만 결국 이해한 내용으로는

  1. N/2마리를 선택해야 하며 → 이 수를 넘을 수 없음.
  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 범위를 넘지 않게 주어집니다.

입출력 예

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으로 시작하지 않습니다.

 

입출력 예

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이하의 자연수입니다.

입출력 예

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)