프로그래머스 level 1

Sawol·2021년 4월 26일
0

algorithm & data structure

목록 보기
17/18
post-thumbnail

크레인 인형뽑기 게임

def solution(board, moves):
    answer = 0
    stack, new_b = [], []
    y:int = len(board)
    for i in range(y):
        new_b.append([b[i] for b in board if b[i]])
    for move in moves:
        if new_b[move-1]:
            toy = new_b[move-1].pop(0)
            if stack and toy == stack[-1]:
                stack.pop()
                answer += 2
            else:
                stack.append(toy)
    return answer

바구니에 인형을 담는 다는 것에서 스택을 이용해야겠다고 생각했다. 처음에는 이중 for문을 사용해서 풀었는데 시간 초과가 나서 코드를 수정했다. board에 들어있는 값중 인형이 들어 있지 않는 0 값은 제외하고 리스트를 행 기준에서 열 기준으로 바꿨다. 그래서 속도가 조금 빨라졌다.

def solution(board, moves):
    basket = []
    result = 0
    for move in moves:
        for i in range(0, len(board)):
            dolls = board[i]
            if dolls[move-1] == 0:
                pass
            else:
                basket.append(dolls[move-1])
                dolls[move-1] = 0
                if len(basket) > 1 and basket[-2] == basket[-1]:
                    basket.pop()
                    basket.pop()
                    result += 2
                    break
                else:
                    break
    return result

이 코드는 알고리즘을 공부하기 전, 옛날에 풀었던 코드다. 확실히 이때에 비해 코드가 간결해졌다.

신규 아이디 추천

import re

def dot(new_id:str):
    if new_id and new_id[0] == '.':
        new_id = new_id[1:]
    if new_id and new_id[-1] == '.':
        new_id = new_id[:-1]
    return new_id

def solution(new_id):
    new_id = re.sub('[^a-z0-9-_.]','', new_id.lower())  # 1 & 2
    while '..' in new_id:    # 3
        new_id = new_id.replace('..','.')
    new_id = dot(new_id)    # 4
    if not new_id:  # 5
        new_id = 'a'
    if len(new_id) >= 16:   # 6
        new_id = new_id[:15]
        new_id = dot(new_id)
    while len(new_id) < 3:  # 7
        new_id += new_id[-1]
    return new_id

while문을 사용하여 ..을 줄이는 건 좋았는데 나머지 코드들은 뭔가 마음에 들지 않았다.

완주하지 못한 선수

def solution(participant:list, completion:list) -> str:
    participant.sort()
    completion.sort()
    for i in range(len(completion)):
        if participant[i] != completion[i]:
            return participant[i]
    return participant[-1]

정렬을 한 상태에서 participantcompletion을 비교하여 다르면 participant값을 리턴한다. 만약 다른 값이 없다면, participant의 마지막 값이 정답이다.

모의고사

def solution(answers):
    solv = [0,0,0]
    f, s, t = list(range(1,6))*2000, [2,1,2,3,2,4,2,5]*(10000//8+1), [3,3,1,1,2,2,4,4,5,5]*1000
    tmp = list(zip(f,s,t))
    for i,v in enumerate(answers):
        for j,w in enumerate(tmp[i]):
            if w == v:
                solv[j] += 1
    answer = [i+1 for i,v in enumerate(solv) if v == max(solv)]

    return answer

f,s,t를 순환을 돌리고 싶은데 방법이 생각안나 최대범위인 10000개로 만들었다. 그 뒤로 zip을 통해 문제 1번의 세명의 정답 순으로 만들어 비교했다.

def solution(answers):
    solv = [0,0,0]
    f, s, t = list(range(1,6)), [2,1,2,3,2,4,2,5], [3,3,1,1,2,2,4,4,5,5]
    for i,v in enumerate(answers):
        if v == f[i%len(f)]:
        	solv[0] += 1
        if v == s[i%len(s)]:
        	solv[1] += 1
        if v == t[i%len(t)]:
        	solv[2] += 1
    answer = [i+1 for i,v in enumerate(solv) if v == max(solv)]

    return answer

다른 사람들의 풀이를 보니 이렇게 패턴의 수를 나눠 나머지 값으로 순환을 시키면 된다. 왜 이 생각을 못 했을까...?😅

from itertools import cycle

def solution(answers):
    solv = [0,0,0]
    f, s, t = cycle(range(1,6)), cycle([2,1,2,3,2,4,2,5]), cycle([3,3,1,1,2,2,4,4,5,5])
    for i,v in enumerate(answers):
        if v == next(f):
        	solv[0] += 1
        if v == next(s):
        	solv[1] += 1
        if v == next(t):
        	solv[2] += 1
    answer = [i+1 for i,v in enumerate(solv) if v == max(solv)]

    return answer

cycle을 사용하면 iterable한 객체를 더 쉽게 순환시킬 수 있다. itertoolsiterable 객체에 엄청나게 다양한 기능을 제공한다는 것을 새삼 다시 한번 느꼈다.
참고로 itertools 모듈은 리턴값은 항상 iterable 객체라는 것을 기억하자.
Reference

체육복

def solution(n, lost, reserve):
    real_lost = set(lost) - set(reserve)
    real_reserve = set(reserve) - set(lost)
    answer = n-len(real_lost)
    for i in sorted(real_lost):
        if i+1 in real_reserve:
            real_reserve.remove(i+1)
            answer += 1
        elif i-1 in real_reserve:
            real_reserve.remove(i-1)
            answer += 1
    return answer

문제 조건에 여벌을 가져왔지만, 도난당한 친구는 체육복을 빌려줄 수 없다 부분을 구현하기 위해 lostreserve의 교집합을 set을 이용해 모두 빼주었다.
그리고 for문을 사용하기 전에 real_lost를 정렬해주어 앞에서 부터 순서대로 비교하도록 구현했다.

def solution(n, lost, reserve):
    real_lost = [l for l in lost if l not in reserve]
    real_reserve = [r for r in reserve if r not in lost]
    answer = n-len(real_lost)
    for i in sorted(real_lost):
        if i+1 in real_reserve:
            real_reserve.remove(i+1)
            answer += 1
        elif i-1 in real_reserve:
            real_reserve.remove(i-1)
            answer += 1
    return answer

앞서 set을 이용한 코드를 위처럼 컴프리헨션으로도 구현할 수 있다.

K번째수

def solution(array, commands):
   return [ sorted(array[i-1:j])[k-1] for i, j, k in commands ]

파이썬의 강점 덕분이겠지만, 너무나도 쉬운 문제.

2016년

def solution(a, b):
    days = ['THU', 'FRI', 'SAT', 'SUN', 'MON', 'TUE', 'WED']
    month_day = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    return days[(sum(month_day[:a])+b)%7]

백준에서 똑같은 문제를 풀었던 기억이 난다. 그때 당시에는 꽤 시간을 들여 고민했었는데, 이제는 바로 코드로 구현할 수 있다. 공부를 내가 열심히 했긴 했구나 싶다.

가운데 글자 가져오기

def solution(s):
    return s[len(s)//2] if len(s)%2 else s[len(s)//2-1:len(s)//2+1]

같은 숫자는 싫어

def solution(arr):
    answer = [-1]
    for i in arr:
        if answer and answer[-1] != i:
            answer.append(i)
    return answer[1:]

리스트가 비어있으면 answer[-1] 에서 오류가 난다. 이를 방지하기 위해 쓰레기 값인 -1를 넣었다.

def solution(arr):
    answer = []
    for i in arr:
        if answer[-1:] != [i]:
            answer.append(i)
    return answer

answer[-1]은 빈 리스트일 때 오류를 발생하지만, answer[-1:]는 오류를 발생안한다!

3진법 뒤집기

def solution(n):
    s = ''
    def base(n):
        if not n:return
        a,b = divmod(n,3)
        base(a)
        nonlocal s
        s = str(b) + s
    base(n)
    return int(s,3)

힘수를 사용하면 깔끔한 코드가 될 줄 알고 작성했는데 조잡해졌다.

def solution(n):
    s = ''
    while n:
        s += str(n%3)
        n //= 3
    return int(s,3)

생각해보면 어차피 3진법을 3진법 n을 구하는 것이 아니라 바로 앞뒤 반전된 3진법 n을 구하면 되는 것이다. 코드가 훨씬 간결해졌다.

음양 더하기

def solution(absolutes, signs):
    return sum([a if s else -a for a,s in zip(absolutes, signs)])

for, if, else 이 세가지를 모두 한 줄 코딩을 하려면 if~else문을 for문 앞에 작성해야한다.

내적

def solution(a, b):
    return sum([a*b for a,b in zip(a,b)])

고등학교 졸업하고 오랜만에 보는 내적...뭔가 반가웠다!

로또의 최고 순위와 최저 순위

def solution(lottos, win_nums):
    hits, zn = len([i for i in win_nums if i in lottos]), lottos.count(0)
    return [7 - zn-hits if hits+zn else 6, 7-hits if hits else 6]

두 개 뽑아서 더하기

import itertools

def solution(numbers):
    return sorted(list(set([a+b for a, b in itertools.combinations(numbers,2)])))

예산

def solution(d, budget):
    answer, m = 0, 0
    d.sort()
    for i in d:
        if m + i <= budget:
            m += i
            answer += 1
    return answer

소수 만들기

import itertools

def solution(nums):
    dp = [False] * 3000
    for i in range(2,3000):
        for j in range(2*i,3000,i):
            dp[j] = True
    return len([dp[sum(i)] for i in itertools.combinations(nums,3) if not dp[sum(i)]])

에라토스테네스의 체로 구현.

나누어 떨어지는 숫자 배열

def solution(arr, divisor):
    answer = [i for i in arr if not i%divisor]
    return [[-1] if not answer else sorted(answer)][0]
def solution(arr, divisor):
    return sorted([i for i in arr if not i%divisor]) or [-1]

or을 이용하면 더욱더 간략하게 표현할 수 있다.

print(10 or 11)	# 둘 다 True이므로 앞에있는 10 출력
print([] or 11) # 11만 True이므로 11 출력

폰켓몬

def solution(nums):
    if len(set(nums)) <= len(nums)//2:
        return len(set(nums))
    return len(nums)//2
def solution(nums):
    return min(len(set(nums),len(nums)//2)

나름 심플하게 풀었다고 생각했는데, 다른 사람들의 코드를 참고하니 위와 같이 한 줄로 작성이 가능하다.

두 정수 사이의 합

def solution(a, b):
    return sum(range(a,b+1) if a < b else range(b,a+1))

문자열 내 마음대로 정렬하기

def solution(strings, n):
    return sorted(sorted(strings), key = lambda x: x[n])

문자열 내 p와 y의 개수

def solution(s):
    return s.lower().count('p') == s.lower().count('y')

문자열 내림차순으로 배치하기

def solution(s):
    return ''.join(sorted(s, reverse=True))

문자열 다루기 기본

def solution(s):
    return (len(s) == 4 or len(s) == 6) and s.isnumeric()

서울에서 김서방 찾기

def solution(seoul):
    return f"김서방은 {seoul.index('Kim')}에 있다"

소수찾기

def solution(n):
    check = [False,False] + [True]*(n-1)
    for i in range(2, n+1):
        if check[i]:
            for j in range(2*i, n+1, i):
                check[j] = False
    return check.count(1)

수박수박수박수박수박수?

import itertools
def solution(n):
    answer = itertools.cycle('수박')
    return ''.join([next(answer) for _ in range(n)])

cycle로 돌려서 수박을 출력한다. 그때 그때 값을 만들기 때문에 메모리 효율도 좋다.

문자열을 정수로 바꾸기

def solution(s):
    return int(s)

시저 암호

import string
def solution(s, n):
    answer = ''
    alpha = string.ascii_lowercase
    for i in s:
        small_i = i.lower()
        if i != ' ':
            if i.isupper():
                answer += alpha[(alpha.index(small_i)+n)%len(alpha)].upper()
            else:
                answer += alpha[(alpha.index(small_i)+n)%len(alpha)]
        else:
            answer += ' '
    return answer

약수의 합

def solution(n):
    return sum([i for i in range(1, n+1) if not n%i])

이상한 문자 만들기

def solution(s):
    answer = []
    s = s.lower().split(' ')
    for i in s:
        tmp = ''
        for j,v in enumerate(i):
            if (j+1)%2:
                tmp += v.upper()
            else:
                tmp += v
        answer.append(tmp)
    return ' '.join(answer)

split()으로 하면 공백을 원소로 취급안한다. split(' ')로 해줘야 공백을 원소로 취급해준다.

자릿수 더하기

def solution(n):
    return sum(list(map(int, str(n))))

자연수 뒤집어 배열로 만들기

def solution(n):
    return list(map(int, str(n)))[::-1]

정수 내림차순으로 배치하기

def solution(n):
    return int(''.join(sorted(list(str(n)), reverse=True)))

정수 제곱근 판별

def solution(n):
    if n**0.5 == int(n**0.5):
        return (n**0.5+1)**2
    return -1

루트(제곱근)을 구할 때 **0.5를 하면 됨!

제일 작은 수 제거하기

def solution(arr):
    arr.remove(min(arr))
    if not arr:
        return [-1]
    return arr

짝수와 홀수

def solution(num):
    if (num+1)%2:
        return "Even"
    return "Odd"

키패트 누르기

def solution(numbers, hand):
    answer = ''
    r, l = [3,6,9], [1,4,7]
    cr, cl = 10, 12
    for i,v in enumerate(numbers):
        if v in r:
            answer += "R"
            cr = v
        elif v in l:
            answer += "L"
            cl = v
        else:
            if v == 0:
                v = 11
            if abs(cr - v)//3+abs(cr - v)%3 < abs(cl - v)//3+abs(cl - v)%3:
                answer += "R"
                cr = v
            elif abs(cr - v)//3+abs(cr - v)%3 > abs(cl - v)//3+abs(cl - v)%3:
                answer += "L"
                cl = v
            else:
                answer += hand[0].upper()
                if hand[0].upper() == 'L':
                    cl = v
                else:
                    cr = v
    return answer

알고리즘을 공부하기 전, 이 문제를 2시간 동안 봤는데 결국 못 풀었다. 이제는 쉽게 느껴지니 뿌듯하다.

최대공약수와 최소공배수

def solution(n, m):
    lcm = n*m
    while m:
        n,m = m,n%m
    return n, lcm//n

최대공약수

def gcd(x,y):
	while y:
    	x,y = y, x%y
    return x

최소공배수

def lcm(x,y):
	return x*y//gcd(x,y)

콜라츠 추측

def solution(num):
    cnt = 0
    while num != 1:
        if cnt == 500:
            return -1
        if num%2:
            num = num*3+1
            cnt += 1
        else:
            num //= 2
            cnt += 1
    return cnt

평균 구하기

def solution(arr):
    return sum(arr)/len(arr)

하샤드 수

def solution(x):
    return not x % sum(map(int, str(x)))

핸드폰 번호 가리기

def solution(phone_number):
    return '*'*(len(phone_number)-4)+phone_number[-4:]

행렬의 덧셈

def solution(arr1, arr2):
    if len(arr1) == len(arr2) and len(arr1[0]) == len(arr2[0]):
        return [list(map(sum, zip(arr1[i],arr2[i]))) for i in range(len(arr1))]

x만큼 간격이 있는 n개의 숫자

def solution(x, n):
    return [x*i for i in range(1,n+1)]

직사각형 별찍기

a, b = map(int, input().strip().split(' '))
print(('*'*a+'\n')*b)

비밀지도

def solution(n, arr1, arr2):
    bmap = [list(format(arr1[i] | arr2[i], 'b').zfill(n)) for i in range(n)]   
    return [''.join(list(map(lambda x: ' ' if x == '0' else '#', j))) for j in bmap]

비트연산
비트 연산을 하려면 십진수를 이진수로 바꿔서 진행해야 하는 줄 알았는데 십진수 그대로도 비트연산이 된다! 예를 들면 아래와 같다.

>> bin(0b1101 & 0b1001)    # 비트 AND
'0b1001'
>> 13 & 9                  # 비트 AND
9
>> bin(0b1101 | 0b1001)    # 비트 OR
'0b1101'
>> 13 | 9                  # 비트 OR
13
>> bin(0b1101 ^ 0b1001)    # 비트 XOR
'0b100'
>> 13 ^ 9                  # 비트 XOR
4
>> bin(~0b1101)            # 비트 NOT
'-0b1110'
>> ~13                     # 비트 NOT
-14

0개의 댓글