본문 바로가기

코딩테스트

[Python] 2024-1 이퍼 준비(1)

# 난이도 <하>

1. 행운의 바퀴(완료)

https://www.acmicpc.net/problem/2840

 

2840번: 행운의 바퀴

첫째 줄에 마지막 회전에서 화살표가 가리키는 문자부터 시계방향으로 바퀴에 적어놓은 알파벳을 출력한다. 이때, 어떤 글자인지 결정하지 못하는 칸은 '?'를 출력한다. 만약, 상덕이가 적어놓

www.acmicpc.net

# 내 풀이
def solution(n, k):
    arr = ["null"]*n
    direct = 0

    for i in range(k): # 거꾸로 저장중. 즉, 출력은 왼쪽(반시계)으로
        s, eng = input().split()
        direct = (direct+int(s))%n
        if (arr[direct]!="null" and arr[direct]!=eng) or eng in arr[:direct] or eng in arr[direct+1:]: # 행운의 바퀴가 존재하지 않는다.
            arr[direct]="!"
            #break
        else:
            arr[direct] = eng 

    for i in range(n):
        if "!" in arr: # !가 있으면
            print("!", end="")
            break
        if arr[direct]=="null":
            print("?", end="")
        else:
            print(arr[direct], end="")
        
        if direct>0:
            direct-=1
        else:
            direct=n-1

n, k = map(int, input().split())
solution(n, k)

 

  • 빈 arr 리스트를 선언한다. 여기에 알아낸 행운의 바퀴를 적을 예정. 처음에 null로 초기화했는데 그냥 ?로 초기화 하고 그대로 출력하는게 좋았을듯.
  • 바퀴가 돌아가는 것 == 화살표가 (반대로) 돌아가는 것. (현재 가리키는 인덱스 direct+회전 수 s)%n 을 하면 회전 후 화살표가 가리키는 바퀴로 간다.
  • 만약 direct가 null이 아닌데 다른 알파벳을 가리키거나...알파벳이 바퀴의 다른 곳에 위치하고 있으면 ! 을 넣은 후 반복문 break. !은 나중에 출력을 위해 사용할 것임.
  • 이제 !가 있으면 ! 출력하고 없으면 알파벳이나 ? 출력하고... direct를 이용해서 출력하고 있다. 저장을 거꾸로(오른쪽으로) 했으므로 출력은 왼쪽으로 해준다. direct를 -1하면서 출력하다가 0이하가 되면 n-1로 저장하기
# 정답 풀이
import sys
input = sys.stdin.readline

"""
[행운의 바퀴]

- 바퀴가 돌아갈 필요 X
- 화살표가 가르키는 인덱스를 회전 정보에 따라 바꿔줌

1. 화살표가 가르키는 칸이 결정되지 않았으면 알파벳을 바퀴에 적는다.
2. 이미 알파벳이 써 있는 경우, 같은 알파벳이 아닌 경우 조건에 해당하는 바퀴 만들 수 없다.
3. 바퀴에 쓰여있는 알파벳은 중복되지 않으므로 동일한 알파벳이 여러 자리에 있을 수 없다.
"""

def solution(n, record):
    wheel = ['?'] * n   # 바퀴의 상태
    is_available = dict()   # 해당 알파벳을 새로 쓸 수 있는지 확인하는 딕셔너리

    # 모든 알파벳에 대해 우선 True로 저장
    # ord(문자) = 아스키코드
    # chr(아스키코드) = 문자
    ord_a = ord('A')
    for i in range(26):
        is_available[chr(i + ord_a)] = True

    idx = 0 # 화살표가 가르키는 인덱스

    for rot, alpha in record:
        idx = (idx - int(rot)) % n
        
        # 같은 경우
        if wheel[idx] == alpha:
            continue
        # 다른 알파벳이 써 있거나, 이미 알파벳을 다른 자리에 사용한 경우
        if wheel[idx] != '?' or not is_available[alpha]:
            return '!'
        wheel[idx] = alpha
        is_available[alpha] = False
                
    return ''.join(wheel[idx:]+wheel[:idx])

# 입력
n, k = map(int, input().split())
record = [input().split() for _ in range(k)]
    
print(solution(n, record))
  • 마찬가지로 바퀴를 저장하는 wheel 리스트를 ?로 초기화 했다.
  • 아스키 코드를 이용하여 문자가 바퀴에 들어갔는지 판별하는 is_available 딕셔너리 선언.
  • 처음에 입력받을 때 record 2차원 배열로 입력 받았네...회전수 rot와 알파벳 alpha를 반복해서 가져온다.
  • ``.join()구문을 이용하여 리스트를 문자열로 바꾸고 연결하였다.

 


 

2. 팰린드롬 만들기

https://www.acmicpc.net/problem/1213

 

1213번: 팰린드롬 만들기

첫째 줄에 문제의 정답을 출력한다. 만약 불가능할 때는 "I'm Sorry Hansoo"를 출력한다. 정답이 여러 개일 경우에는 사전순으로 앞서는 것을 출력한다.

www.acmicpc.net

# 내 풀이
def solution(name):
    arr = sorted(name)
    name2=[]
    direct=0
    one='null'

    while(direct<len(name)):
        if arr.count(arr[direct])%2==0:
            name2.append(arr[direct])
            direct +=2
        elif arr.count(arr[direct])%2==1 and arr.count(arr[direct])>2:
            name2.append(arr[direct])
            if one!='null':
                name2=""
                break
            one = arr[direct]
            arr[direct]="?"
            direct+=3
        else:
            if one!='null':
                name2=""
                break
            one = arr[direct]
            direct += 1
    n = len(name2)
    if n<=0 and len(name)>1:
        print("I'm Sorry Hansoo")
    else:
        if one != "null":
            name2.append(one)
        for i in range(n):
            name2.append(name2[n-i-1])

        print(''.join(name2))

solution(input())
  • 일단 입력받은 name을 정렬해서 리스트 arr에 저장했다. 
  • 검사할 인덱스를 가리키는 direct를 가지고 name의 길이만큼 반복한다.
  • direct가 가리키는 문자가 짝수면 팰린드롬이 될 name2 리스트에 추가한 후 direct +2(다음 문자도 무조건 같으므로)
  • 만약 direct가 가리키는 문자가 홀수이고 3이상이라면, name2에 일단 추가하고 하나의 문자만 저장하는 one에 저장한다.
  • 단, 이때 one에 다른 문자가 있으면 팰린드롬이 절대 안되므로 탈락.(name2를 null로 만들고 break.)그리고 해당 문자하나를 없애준 후 direct +3(다음 다다음 문자는 무조건 같음)
  •  만약 전부 아니면, 즉 direct가 가리키는 문자가 홀수이고 하나만 존재한다면 위를 반복한다. 대신 driect는 +1
  • 이제 팰린드롬을 만든다. name2의 길이가 0이하이고 name의 길이가 1보다 크다면 팰린드롬이 만들어지지 않은 것이므로 문자열 출력.
  • 만약 팰린드롬이 가능하다면...one의 여부에따라 약간 다르게 팰린드롬의 나머지를 채운 후 print한다.
# 정답 풀이
import sys
from collections import Counter

input = sys.stdin.readline


def make_palindrome(text):
    # 각 알파벳의 수를 가지고 팰린드롬 문자열을 리턴하는 함수
    # 만들 수 없으면 "I'm Sorry Hansoo" 리턴
    part1 = ""
    part2 = ""

    # Counter(text): 각 문자가 몇개씩 들어있는지 dictionary 형태로 돌려줌
    # .items() : key와 value를 짝 지어서 돌려줌
    # sorted - 사전적으로 가장 앞서는 문자열을 만들기 위해 정렬
    alphabets = sorted(Counter(text).items())

    for key, value in alphabets:
        if value % 2 == 1:
            # 만약 가운데 글자가 있다면 더 이상 불가능
            if len(part2) == 1:
                # 주의! 문자열에 '가 들어있기 때문에, ""로 감싸주어야 합니다.
                return "I'm Sorry Hansoo"
            # 비어있다면, 할당
            part2 = key

        part1 += key * (value // 2)

    return part1 + part2 + part1[::-1]


def solution(input):
    return make_palindrome(input)


if __name__ == "__main__":
    # 입력
    text = input().rstrip()
    answer = solution(text)
    print(answer)
  • counter 함수를 이용해서 alphabets 딕셔너리에 {알파벳 : 알파벳 갯수}로 저장 후 정렬하였다.
  • 이제 여기서 alphabets를 돌아준다. value값이 홀수라면 part2에 해당 알파벳을 저장한다. 만약 이미 part2가 있다면, 문자열 출력
  • 홀수가 아니면 part1에 알파벳*(알파벳 갯수/2)해서 추가.
  • return은 part1 + part2 + part1[::-1]로 간단해서 역순 문자열을 추가했다...
  • 입력받을 때 혹시 몰라 공백을 제거했네. 안해도 통과는 됐었음.

3. 쇠막대기

https://www.acmicpc.net/problem/10799

 

10799번: 쇠막대기

여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저

www.acmicpc.net

# 내 풀이
def solution(stick):
    st1=[]
    num=0 
    s=0 # stick 검사

    stick = list(stick)

    while (s < len(stick)):
        # print(st1)
        if stick[s]=="(" and stick[s+1]==")":
            num += len(st1)
            s+=2
            continue
        else:
            if stick[s]=="(":
                st1.append("(")
            else:
                num += 1
                st1.pop()
            s+=1
    print(num)
solution(input())
  • 일단 stick을 리스트로 바꾼다. stick을 검사할 인덱스 s와 막대기를 저장하기 위한 스택 st1을 선언.
  • 만약 (), 즉 레이저가 있다면 스택에 들어있는 막대기의 수만큼 결과 num에 저장하면 된다. 예를 들어, (((())()))의 경우에 처음 ()를 마주하면 스택에 ((( 3개가 저장되어 있으므로 num +3(st1의 길이)
  • ()가 연속으로 붙어있지 않으면 막대기 이므로 잘 판별해서 (인 경우 st1에 넣고 )인 경우 st1에서 하나 빼고 반복해준다.
  • 이때 )를 할 경우에는 num+=1을 해주어야 함.
# 정답 풀이
import sys

def solution(s):
    answer = 0
    stack = []

    for i in range(len(s)):
        # 여는 괄호인 경우, stack에 push
        if s[i] == "(":
            stack.append("(")

        # 닫힌 괄호인 경우
        else:
            stack.pop()

            # 이전 문자가 '('라면 레이저
            if s[i - 1] == "(":
                # 레이저이면 stack size만큼 더하기
                answer += len(stack)
            # 이전 문자가 ')'라면 쇠막대기의 끝
            else:
                # 쇠막대기의 끝이면 +1
                answer += 1

    return answer
    
#str()은 함수이름이므로 s를 사용.
if __name__ == "__main__":
    s = sys.stdin.readline().strip()
    answer = solution(s)
    print(answer)
  • 위랑 비슷함.

 


# 회고

 

 

구현은 참 문제 이해부터 어렵다.

겁나 열심히 어찌어찌 풀긴 풀었는데 정답은 쉽게 한거보면 슬프구만.

내가 이해를 잘 못해서 그런가 실제 시험때 반례를 못찾아서 망할 것 같은 느낌임 ㅜ

 

그리고 대비 문제는 백준으로 주는데 왜 시험은 프로그래머스로 보는가. 하나만 했으면 좋겠다.