[프로그래머스] [Python] (Level 2) 할인 행사
https://school.programmers.co.kr/learn/courses/30/lessons/131127 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요. programmers.co.kr 문제 더보기 XYZ 마트는 일정한 금액을 지불하면 10일 동안 회원 자격을 부여합니다. XYZ 마트에서는 회원을 대상으로 매일 한 가지 제품을 할인하는 행사를 합니다. 할인하는 제품은 하루에 하나씩만 구매할 수 있습니다. 알뜰한 정현이는 자신이 원하는 제품과 수량이 할인하는 날짜와 10일 연속으로 일치할 경우에 맞춰서 회원가입을 하려 합니다. 예를 들어, 정현이가 원하는 제품이 바나나 3개, 사..
2023.08.06
[Python] collections 모듈의 Counter 사용방법
Collections 모듈에서의 Counter 객체 Counter은 객체를 계산하기 위한 dict의 하위 클래스 입니다. 요소는 dictionary의 키로 저장되며 그들의 갯수는 dictionary의 value 값으로 저장되는 collection입니다. value 값은 0 또는 음수를 포함해 모둔 '정수' 값이 될 수 있습니다. 참고링크 Counter 선언방법 선언하는 방법은 2가지가 있습니다. collections 모듈에서 Counter을 불러오는 방식입니다. from collections import Counter # 방법 1 counter1 = Counter() collections 모듈을 모두 불러와 collections를 접두사로 사용하는 방식입니다. import collections # 방법 ..
2023.07.30
no image
[프로그래머스] [Python] (Level 2) 우박수열 정적분
https://school.programmers.co.kr/questions/41525 프로그래머스코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.programmers.co.kr문제더보기콜라츠 추측이란 로타르 콜라츠(Lothar Collatz)가 1937년에 제기한 추측으로 모든 자연수 n에 대해 다음 작업을 반복하면 항상 1로 만들 수 있다는 추측입니다.1-1. 입력된 수가 짝수라면 2로 나눕니다.1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다.2.결과로 나온 수가 1보다 크다면 1번 작업을 반복합니다.예를 들어 주어진 수가 5 라면 5 ⇒ 16 ⇒ 8 ⇒ 4 ⇒2 ⇒ 1 이되어 총 5번만에..
2023.07.30
no image
[BOJ] [Python] 17069번 : 파이프 옮기기 2
https://www.acmicpc.net/problem/17069 17069번: 파이프 옮기기 2 유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의 www.acmicpc.net 문제 및 입출력 더보기 문제 유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의 번호이고, 행과 열의 번호는 1부터 시작한다. 각각의 칸은 빈 칸이거나 벽이다. 오늘은 집 수리를 위해서 파이프 하나를 옮기려고 한다. ..
2023.07.24
no image
[BOJ] [Python] 15992번 : 1, 2, 3 더하기 7
https://www.acmicpc.net/problem/15992 15992번: 1, 2, 3 더하기 7 각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 1,000,000,009로 나눈 나머지를 출력한다. 단, 사용한 수의 개수는 m개 이어야 한다. www.acmicpc.net 문제 더보기 정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다. 1+1+1+1 1+1+2 1+2+1 2+1+1 2+2 1+3 3+1 정수 n과 m이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오. 단, 사용한 수의 개수는 m개 이어야 한다. 입출력 보기 더보기 입력 첫째 줄에 테스트 케이스의..
2023.07.13
[프로그래머스] [Python] (Level 3) 인사고과 ( + 추가 test case)
문제 더보기 완호네 회사는 연말마다 1년 간의 인사고과에 따라 인센티브를 지급합니다. 각 사원마다 근무 태도 점수와 동료 평가 점수가 기록되어 있는데 만약 어떤 사원이 다른 임의의 사원보다 두 점수가 모두 낮은 경우가 한 번이라도 있다면 그 사원은 인센티브를 받지 못합니다. 그렇지 않은 사원들에 대해서는 두 점수의 합이 높은 순으로 석차를 내어 석차에 따라 인센티브가 차등 지급됩니다. 이때, 두 점수의 합이 동일한 사원들은 동석차이며, 동석차의 수만큼 다음 석차는 건너 뜁니다. 예를 들어 점수의 합이 가장 큰 사원이 2명이라면 1등이 2명이고 2등 없이 다음 석차는 3등부터입니다. 각 사원의 근무 태도 점수와 동료 평가 점수 목록 scores이 주어졌을 때, 완호의 석차를 return 하도록 soluti..
2023.07.07
[프로그래머스] [Python] (Level 2) 혼자서 하는 틱택토 (+ 추가 test case)
https://school.programmers.co.kr/learn/courses/30/lessons/160585 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요. programmers.co.kr 문제 더보기 틱택토는 두 사람이 하는 게임으로 처음에 3x3의 빈칸으로 이루어진 게임판에 선공이 "O", 후공이 "X"를 번갈아가면서 빈칸에 표시하는 게임입니다. 가로, 세로, 대각선으로 3개가 같은 표시가 만들어지면 같은 표시를 만든 사람이 승리하고 게임이 종료되며 9칸이 모두 차서 더 이상 표시를 할 수 없는 경우에는 무승부로 게임이 종료됩니다. 할 일이 없어 한가한 머쓱이는 두 사람이 하는..
2023.07.06
no image
[프로그래머스] [Python] (Level 2) 미로 탈출
https://school.programmers.co.kr/learn/courses/30/lessons/159993 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요. programmers.co.kr 문제 1 x 1 크기의 칸들로 이루어진 직사각형 격자 형태의 미로에서 탈출하려고 합니다. 각 칸은 통로 또는 벽으로 구성되어 있으며, 벽으로 된 칸은 지나갈 수 없고 통로로 된 칸으로만 이동할 수 있습니다. 통로들 중 한 칸에는 미로를 빠져나가는 문이 있는데, 이 문은 레버를 당겨서만 열 수 있습니다. 레버 또한 통로들 중 한 칸에 있습니다. 따라서, 출발 지점에서 먼저 레버가 있는 칸으로 이동..
2023.07.03
[프로그래머스] [Python] (Level 2) 과제 진행
https://school.programmers.co.kr/learn/courses/30/lessons/176962 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요. programmers.co.kr 문제 과제를 받은 루는 다음과 같은 순서대로 과제를 하려고 계획을 세웠습니다. 과제는 시작하기로 한 시각이 되면 시작합니다. 새로운 과제를 시작할 시각이 되었을 때, 기존에 진행 중이던 과제가 있다면 진행 중이던 과제를 멈추고 새로운 과제를 시작합니다. 진행중이던 과제를 끝냈을 때, 잠시 멈춘 과제가 있다면, 멈춰둔 과제를 이어서 진행합니다. 만약, 과제를 끝낸 시각에 새로 시작해야 되는 과제와..
2023.07.03
[Python] deque를 list 대신 써야하는 이유가 뭘까?
deque 이란? 결론부터 말씀드리자면 list 와 같은 배열이지만 "양쪽에서 요소를 추가와 삭제가 가능한" 자료구조입니다. Python의 collections 모듈에서 제공하는 deque는 "double-ended queue"(양방향 큐)의 줄임말 입니다. 다시 말해서 queue(큐)에 앞쪽에 연산이 추가된 자료구조라고 볼 수 있습니다. 써야하는 이유 deque 자료구조는 pop, append method는 시간복잡도가 O(1)입니다. 하지만 list 자료구조에서 pop, append method는 시간복잡도가 O(n)입니다. 이러한 이유로 작은 데이터 셋에서는 큰 차이가 없지만 데이터 셋이 큰 경우에 큰 차이를 알 수 있습니다. 특히 BFS를 queue로 구현하면 시간초과가 발생하지만 deque를 통..
2023.06.25
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/131127

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제


더보기

XYZ 마트는 일정한 금액을 지불하면 10일 동안 회원 자격을 부여합니다. XYZ 마트에서는 회원을 대상으로 매일 한 가지 제품을 할인하는 행사를 합니다. 할인하는 제품은 하루에 하나씩만 구매할 수 있습니다. 알뜰한 정현이는 자신이 원하는 제품과 수량이 할인하는 날짜와 10일 연속으로 일치할 경우에 맞춰서 회원가입을 하려 합니다.

예를 들어, 정현이가 원하는 제품이 바나나 3개, 사과 2개, 쌀 2개, 돼지고기 2개, 냄비 1개이며, XYZ 마트에서 15일간 회원을 대상으로 할인하는 제품이 날짜 순서대로 치킨, 사과, 사과, 바나나, 쌀, 사과, 돼지고기, 바나나, 돼지고기, 쌀, 냄비, 바나나, 사과, 바나나인 경우에 대해 알아봅시다. 첫째 날부터 열흘 간에는 냄비가 할인하지 않기 때문에 첫째 날에는 회원가입을 하지 않습니다. 둘째 날부터 열흘 간에는 바나나를 원하는 만큼 할인구매할 수 없기 때문에 둘째 날에도 회원가입을 하지 않습니다. 셋째 날, 넷째 날, 다섯째 날부터 각각 열흘은 원하는 제품과 수량이 일치하기 때문에 셋 중 하루에 회원가입을 하려 합니다.

정현이가 원하는 제품을 나타내는 문자열 배열 want와 정현이가 원하는 제품의 수량을 나타내는 정수 배열 number, XYZ 마트에서 할인하는 제품을 나타내는 문자열 배열 discount가 주어졌을 때, 회원등록시 정현이가 원하는 제품을 모두 할인 받을 수 있는 회원등록 날짜의 총 일수를 return 하는 solution 함수를 완성하시오. 가능한 날이 없으면 0을 return 합니다.

 

입출력( + 추가적인 Test Case)


더보기
want number discount result
["chicken", "apple", "apple", "banana", "rice", "apple", "pork", "banana", "pork", "rice", "pot", "banana", "apple", "banana"] [3, 2, 2, 2,1] ["chicken", "apple", "apple", "banana", "rice", "apple", "pork", "banana", "pork", "rice", "pot", "banana", "apple", "banana"] 3
["apple"] [10] ["banana", "banana", "banana", "banana", "banana", "banana", "banana", "banana", "banana", "banana"] 6

제한사항


더보기
  • 1 ≤ want의 길이 = number의 길이 ≤ 10
    • 1 ≤ number의 원소 ≤ 10
    • number[i]는 want[i]의 수량을 의미하며, number의 원소의 합은 10입니다.
  • 10 ≤ discount의 길이 ≤ 100,000
  • want와 discount의 원소들은 알파벳 소문자로 이루어진 문자열입니다.
    • 1 ≤ want의 원소의 길이, discount의 원소의 길이 ≤ 12

풀이방법


유저의 쇼핑목록과 개수를 Counter class 로 구성합니다.

1일차부터 n, len(discount)-9 일까지의 각각의 카운터를 구성합니다.

만약 user_counter 와 mart_counter가 동일하다면 answer 을 1씩 더합니다.

마지막 answer을 반환합니다.

 

코드


from collections import Counter

def solution(want, number, discount):
    answer = 0
    user = dict()
    for i in zip(want,number):
        user[i[0]] = i[1]
    user_counter = Counter(user)
    for i in range(0,len(discount)-sum(number)+1):
        mart = Counter(discount[i:i+10])
        if user_counter == mart:
            answer += 1
    return answer
728x90
728x90

Collections 모듈에서의 Counter 객체


Counter은 객체를 계산하기 위한 dict의 하위 클래스 입니다. 요소는 dictionary의 키로 저장되며 그들의 갯수는 dictionary의 value 값으로 저장되는 collection입니다. value 값은 0 또는 음수를 포함해 모둔 '정수' 값이 될 수 있습니다.

참고링크

 

 

Counter 선언방법


선언하는 방법은 2가지가 있습니다.

collections 모듈에서 Counter을 불러오는 방식입니다.

from collections import Counter # 방법 1

counter1 = Counter()

collections 모듈을 모두 불러와 collections를 접두사로 사용하는 방식입니다.

import collections # 방법 2

counter2 = collections.Counter()

밑에 설명하는 코드들은 방법 1을 사용해서 선언하도록 하겠습니다.

 

 

리스트(List) 와 카운터(Counter)


a = ['aaa','ddd','aaa','ccc','aaa','ccc','bbb','aaa']

counter = Counter(a)
print(counter)
>>> Counter({'aaa': 4, 'ccc': 2, 'ddd': 1, 'bbb': 1})

Counter의 type은 dict입니다.

list를 Counter를 통해 선언한다면, 반환하는 type은 Counter객체이지만 Counter 안에 있는 type은 dict입니다.

출력은 value값의 순서대로 출력합니다.(내림차순) 하지만 value가 같은 경우 key는 내림차순이 아닙니다.

딕셔너리(dictionary)와 카운터(Counter)


a = {'k': 5, 's': 1, 'c': 4}

counter = Counter(a)
print(counter)
>>> Counter({'k': 5, 'c': 4, 's': 1})

dict를 Counter을 통해 선언한다면 value값의 내림차순으로 출력합니다.하지만 value가 같은 경우 key는 내림차순이 아닙니다.

 

 

문자열(String)과 카운터(Counter)


a = 'aasdfasdf'

counter = Counter(a)
print(counter)
>>> Counter({'a': 3, 's': 2, 'd': 2, 'f': 2})

위와 다르게 이번엔 문자열(String)을 카운터(Counter)에 넣어서 반환하는 방식을 구현했습니다.

문자열별로 얼마나 count되었는지 확인할 수 있습니다.

 

숫자(integer)와 카운터(Counter)


a = 323124

counter = Counter(a)
print(counter)

Traceback (most recent call last):
  File "/Users/hwangiljeong/PycharmProjects/pythonProject/main.py", line 6, in <module>
    counter = Counter(a)
              ^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/collections/__init__.py", line 597, in __init__
    self.update(iterable, **kwds)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/collections/__init__.py", line 688, in update
    _count_elements(self, iterable)
TypeError: 'int' object is not iterable

정수는 오류가 not iterable 하기 때문에 오류가 발생합니다.

 

Counter의 함수들을 소개해보겠습니다.

 

element() 


c = Counter(a=4, b=2, c=0, d=-2)
print(sorted(c.elements())

>>> ['a', 'a', 'a', 'a', 'b', 'b']

개수만큼 반복되는 요소에 대한 이터레이터를 반환합니다. 요소는 처음 발견되는 순서대로 반환됩니다. 요소의 개수가 1보다 작으면 elements()는 이를 무시합니다.

 

most_common(n)


a = 'blogblogblogg'

counter = Counter(a)
print(counter.most_common())
>>> [('g', 4), ('b', 3), ('l', 3), ('o', 3)]

print(counter.most_common(2))
>>> [('g', 4), ('b', 3)]

n 개의 가장 흔한 요소와 그 개수를 가장 흔한 것부터 가장 적은 것 순으로 나열한 리스트를 반환합니다. 

n이 생략되거나 None이면, most_common()은 계수기의 모든 요소를 반환합니다. 개수가 같은 요소는 처음 발견된 순서를 유지합니다.

 

 

subtract()


c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
c.subtract(d)
# c의 counter - d의 counter 

print(c)
>>> Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
# 각각의 요소를 뺀 값들을 출력

이터러블이나 다른 매핑 (또는 계수기)으로부터 온 요소들을 뺍니다. 입력과 출력 모두 0이나 음수일 수 있습니다.

 

Counter 활용방법


c = Counter('blogblogblogg')
c.total()                       # count의 총 개수
>>> 13

c = Counter('blogblogblogg')
c.clear()                       # 요소를 모두 제거
>>> None

c = Counter('blogblogblogg')
list(c)                         # 요소들을 list로 출렫하되 중복을 제거합니다.
>>> ['b', 'l', 'o', 'g']

c = Counter('blogblogblogg')
set(c)                          # set 형으로 변환합니다.
>>> {'b', 'o', 'g', 'l'}

c = Counter('blogblogblogg')
dict(c)                         # dictionary로 변환합니다.
>>> {'b': 3, 'l': 3, 'o': 3, 'g': 4}

c = Counter('blogblogblogg')
c.items()                       # (elem, cnt) 이러한 형태로 변환합니다.
>>> dict_items([('b', 3), ('l', 3), ('o', 3), ('g', 4)])

 

Counter 연산


c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
print(c + d)                       # add two counters together:  c[x] + d[x]
>>> Counter({'a': 4, 'b': 3})
print(c - d)                       # subtract (keeping only positive counts)
>>> Counter({'a': 2})
print(c & d)                       # intersection:  min(c[x], d[x])
>>> Counter({'a': 1, 'b': 1})
print(c | d)                       # union:  max(c[x], d[x])
>>> Counter({'a': 3, 'b': 2})
print(c == d)                      # equality:  c[x] == d[x]
>>> False
print(c <= d)                      # inclusion:  c[x] <= d[x]
>>> False
728x90
728x90

https://school.programmers.co.kr/questions/41525

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제


더보기

콜라츠 추측이란 로타르 콜라츠(Lothar Collatz)가 1937년에 제기한 추측으로 모든 자연수 n에 대해 다음 작업을 반복하면 항상 1로 만들 수 있다는 추측입니다.

1-1. 입력된 수가 짝수라면 2로 나눕니다.
1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다.
2.결과로 나온 수가 1보다 크다면 1번 작업을 반복합니다.

예를 들어 주어진 수가 5 라면 5 ⇒ 16 ⇒ 8 ⇒ 4 ⇒2 ⇒ 1 이되어 총 5번만에 1이 됩니다.

수가 커졌다 작아지기를 반복하는 모습이 비구름에서 빗방울이 오르락내리락하며 우박이 되는 모습과 비슷하다고 하여 우박수 또는 우박수열로 불리기도 합니다. 현재 이 추측이 참인지 거짓인지 증명되지 않았지만 약 1해까지의 수에서 반례가 없음이 밝혀져 있습니다.

은지는 우박수열을 좌표 평면 위에 꺾은선 그래프로 나타내보려고 합니다. 초항이 K인 우박수열이 있다면, x = 0일때 y = K이고 다음 우박수는 x = 1에 표시합니다. 이런 식으로 우박수가 1이 될 때까지 점들을 찍고 인접한 점들끼리 직선으로 연결하면 다음과 같이 꺾은선 그래프를 만들 수 있습니다.

은지는 이렇게 만든 꺾은선 그래프를 정적분 해보고 싶어졌습니다. x에 대한 어떤 범위 [a, b]가 주어진다면 이 범위에 대한 정적분 결과는 꺾은선 그래프와 x = a, x = b, y = 0 으로 둘러 쌓인 공간의 면적과 같습니다. 은지는 이것을 우박수열 정적분이라고 정의하였고 다양한 구간에 대해서 우박수열 정적분을 해보려고 합니다.

단, 우박수열 그래프의 가로축 길이를 미리 알 수 없기 때문에 구간의 시작은 음이 아닌 정수, 구간의 끝은 양이 아닌 정수로 표현합니다. 이는 각각 꺾은선 그래프가 시작하는 점과 끝나는 점의 x좌표에 대한 상대적인 오프셋을 의미합니다.

예를 들어, 5를 초항으로 하는 우박수열은 5 ⇒ 16 ⇒ 8 ⇒ 4 ⇒ 2 ⇒ 1 입니다. 이를 좌표 평면으로 옮기면 (0, 5), (1, 16), (2, 8), (3, 4), (4, 2), (5, 1) 에 점이 찍히고 점들을 연결하면 꺾은선 그래프가 나옵니다. 이를 [0,0] 구간에 대해 정적분 한다면 전체 구간에 대한 정적분이며, [1,-2] 구간에 대해 정적분 한다면 1 ≤ x ≤ 3인 구간에 대한 정적분입니다.

우박수의 초항 k와, 정적분을 구하는 구간들의 목록 ranges가 주어졌을 때 정적분의 결과 목록을 return 하도록 solution을 완성해주세요. 단, 주어진 구간의 시작점이 끝점보다 커서 유효하지 않은 구간이 주어질 수 있으며 이때의 정적분 결과는 -1로 정의합니다.

 

입출력( + 추가적인 Test Case)


k ranges result
5 [[0,0],[0,-1],[2,-3],[3,-3]] [33.0,31.5,0.0,-1.0]
5 [[8,0]] [-1.0]

제한사항


더보기

 

  • 2 ≤ k ≤ 10,000
  • 1 ≤ ranges의 길이 ≤ 10,000
    • ranges의 원소는 [a, b] 형식이며 0 ≤ a < 200, -200 < b ≤ 0 입니다.
  • 주어진 모든 입력에 대해 정적분의 결과는 227 을 넘지 않습니다.
  • 본 문제는 정답에 실수형이 포함되는 문제입니다. 입출력 예의 소수 부분 .0이 코드 실행 버튼 클릭 후 나타나는 결괏값, 기댓값 표시와 다를 수 있습니다.

풀이방법


1. k에 대한 우박수열을 구합니다.

2. 각각의 구간에 대해 넓이를 구합니다. ex) 0 ~ 1 구간, 1 ~ 2 구간 등등등

3. ranges 를 index 형식으로 변환합니다.(k 수열의 길이가 7인 경우, [0, 0] -> [0, 7])

3-1.  변환 후 뒤의 숫자가 앞의 숫자보다 작은 경우 -1.0 을 반환합니다. ex) [6,3]

4. 각각의 구간의 합을 구한 뒤 반환합니다.

 

코드


def solution(k, ranges):
	
    # 우박수열
    k_list = [k]
    while k != 1:
        if k % 2 == 0:
            k = k// 2
            k_list.append(k)
        else:
            k = k * 3 + 1
            k_list.append(k)

	# 각각의 구간의 넓이
    integral = []
    for i in range(len(k_list)-1):
        temp = (k_list[i]+k_list[i+1])/2
        integral.append(temp)

	# index 변환 및 범위 판단 후 넓이를 list에 추가
    answer = []
    for i in ranges:
        a,b = i[0], len(k_list)+i[1]-1
        if b < a:
            answer.append(-1.0)
        else:
            answer.append(float(sum(integral[a:b])))
    return answer

 

728x90
728x90

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

 

17069번: 파이프 옮기기 2

유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의

www.acmicpc.net

문제 및 입출력 

 

더보기

문제

유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의 번호이고, 행과 열의 번호는 1부터 시작한다. 각각의 칸은 빈 칸이거나 벽이다.

오늘은 집 수리를 위해서 파이프 하나를 옮기려고 한다. 파이프는 아래와 같은 형태이고, 2개의 연속된 칸을 차지하는 크기이다.

 

파이프는 회전시킬 수 있으며, 아래와 같이 3가지 방향이 가능하다.

 

파이프는 매우 무겁기 때문에, 유현이는 파이프를 밀어서 이동시키려고 한다. 벽에는 새로운 벽지를 발랐기 때문에, 파이프가 벽을 긁으면 안 된다. 즉, 파이프는 항상 빈 칸만 차지해야 한다.

파이프를 밀 수 있는 방향은 총 3가지가 있으며, →, ↘, ↓ 방향이다. 파이프는 밀면서 회전시킬 수 있다. 회전은 45도만 회전시킬 수 있으며, 미는 방향은 오른쪽, 아래, 또는 오른쪽 아래 대각선 방향이어야 한다.

파이프가 가로로 놓여진 경우에 가능한 이동 방법은 총 2가지, 세로로 놓여진 경우에는 2가지, 대각선 방향으로 놓여진 경우에는 3가지가 있다.

아래 그림은 파이프가 놓여진 방향에 따라서 이동할 수 있는 방법을 모두 나타낸 것이고, 꼭 빈 칸이어야 하는 곳은 색으로 표시되어져 있다.

가장 처음에 파이프는 (1, 1)와 (1, 2)를 차지하고 있고, 방향은 가로이다. 파이프의 한쪽 끝을 (N, N)로 이동시키는 방법의 개수를 구해보자.

입력

첫째 줄에 집의 크기 N(3 ≤ N ≤ 32)이 주어진다. 둘째 줄부터 N개의 줄에는 집의 상태가 주어진다. 빈 칸은 0, 벽은 1로 주어진다. (1, 1)과 (1, 2)는 항상 빈 칸이다.

 

출력

첫째 줄에 파이프의 한쪽 끝을 (N, N)으로 이동시키는 방법의 수를 출력한다. 이동시킬 수 없는 경우에는 0을 출력한다.

 

풀이방법

 

처음의 파이프는 이와 같이 가로로 되어 있습니다. 

입력받은 N x N 의 DP행렬을 생성합니다. 각각의 행렬안에는 크기가 3인 배열이 있으며 각각 대각선, 세로, 가로입니다.

처음 파이프가 가로로 놓아져있을 때의 초기값입니다.

* 입력받은 행렬을 matrix로 표현합니다.

이후 DP[i][j]의 칸의 값을 구하는 방법은 다음과 같습니다.

 

(대각선)

matrix[i-1][j-1], matrix[i-1][j], matrix[i][j-1]의 칸이 모두 0인 경우 (모두 벽이 아닌 빈칸)

DP[i][j][0] = sum(DP[i-1][j-1])

 

(세로)

matrix[i-1][j-1] 이 0인 경우(벽이 아닌 빈칸)

현재칸의 세로 파이프 = 위칸에서의 대각선으로 들어온 파이프 + 위칸에서의 세로로 들어온 파이프

dp[i][j][1] = dp[i-1][j][0] + dp[i-1][j][1]

 

(가로)

matrix[i-1][j-1] 이 0인 경우(벽이 아닌 빈칸)

현재칸의 가로 파이프 = 왼쪽칸에서의 대각선으로 들어온 파이프 + 왼쪽칸에서의 가로로 들어온 파이프

dp[i][j][2] = dp[i][j-1][0] + dp[i][j-1][2]

 

 

코드

import sys

# 입력
N = int(input())
matrix = [list(map(int,sys.stdin.readline().rstrip().split())) for _ in range(N)]
# 대각선, 세로, 가로
dp = [[[0] * 3 for _ in range(N+1)] for __ in range(N+1)]
dp[1][2][2] = 1
for i in range(1,N+1):
    for j in range(3, N+1):
        if matrix[i-1][j-1] == 0:
            # 대각선
            if matrix[i-1][j-2] == 0 and matrix[i-2][j-1] == 0:
                dp[i][j][0] = sum(dp[i-1][j-1])
            # 세로
            dp[i][j][1] = dp[i-1][j][0] + dp[i-1][j][1]
            # 가로
            dp[i][j][2] = dp[i][j-1][0] + dp[i][j-1][2]

print(sum(dp[N][N]))

결론

처음의 초기값을 잘 주는 것을 성공적으로해서 생각보다 빨리 풀 수 있었습니다.

마지막 DP배열을 증가시키는 과정에서 다른 방법을 쓰면 DP배열을 확장하지 않아도 될 것 같지만 코드의 가독성을 위해 썼습니다.

 

728x90
728x90

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

 

15992번: 1, 2, 3 더하기 7

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 1,000,000,009로 나눈 나머지를 출력한다. 단, 사용한 수의 개수는 m개 이어야 한다.

www.acmicpc.net

문제

더보기

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.

  • 1+1+1+1
  • 1+1+2
  • 1+2+1
  • 2+1+1
  • 2+2
  • 1+3
  • 3+1

정수 n과 m이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오. 단, 사용한 수의 개수는 m개 이어야 한다.

 

입출력 보기

더보기

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n과 m이 주어진다. n은 양수이며 1,000보다 작거나 같다. m도 양수이며, n보다 작거나 같다.

 

출력

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 1,000,000,009로 나눈 나머지를 출력한다. 단, 사용한 수의 개수는 m개 이어야 한다.

 

풀이방법

m = 수의 합, n = 사용한 수의 개수

왼쪽의 표를 보게 되면 형광색으로 칠한 것의 합이 빨간색 화살표로 가리킨 숫자와 같습니다.

그 이유는 오른쪽의 한 예시를 보면 알 수 있습니다. 

예시) f(4,2)에서  1 + 3, 2 + 2, 3 + 1 이렇게 3개의 숫자입니다. 이 숫자들은 각각 1, 2, 3에 3, 2, 1를 더한 것입니다.

이 예시를 통해 정리한 식은 우하단의 식과 같습니다.

f(m, n) = f(m-1, n-1) + f(m-2, n-1) + f(m-3, n-1) -> 각각의 수들에서 1, 2, 3을 더한 수들의 합이라고 보시면 됩니다. 

 

 

 

코드

import sys

input=sys.stdin.readline
MAX = 1001
MOD = 1_000_000_009

# 초기값 설정
dp = [[0] * MAX for _ in range(MAX)]
dp[1][1] = 1
dp[2][1], dp[2][2] = 1,1
dp[3][1], dp[3][2], dp[3][3] = 1, 2, 1

for i in range(4, MAX):
    for j in range(1, i + 1):
        dp[i][j] = (dp[i-1][j-1] + dp[i-2][j-1] + dp[i-3][j-1]) % MOD

# 출력
N = int(input())
for i in range(N):
    n, m = map(int, input().split())
    print(dp[n][m])
728x90

'Algorithm > BOJ' 카테고리의 다른 글

[BOJ] [Python] 3187번 : 양치기 꿍  (0) 2023.08.27
[BOJ] [Python] 17069번 : 파이프 옮기기 2  (0) 2023.07.24
[BOJ] [Python] 15828번 : Router  (0) 2023.06.24
[BOJ] [Python] 2164번 : 카드2  (0) 2023.06.23
[BOJ] [Python] 10845번 큐  (0) 2023.06.23
728x90

문제


더보기

완호네 회사는 연말마다 1년 간의 인사고과에 따라 인센티브를 지급합니다. 각 사원마다 근무 태도 점수와 동료 평가 점수가 기록되어 있는데 만약 어떤 사원이 다른 임의의 사원보다 두 점수가 모두 낮은 경우가 한 번이라도 있다면 그 사원은 인센티브를 받지 못합니다. 그렇지 않은 사원들에 대해서는 두 점수의 합이 높은 순으로 석차를 내어 석차에 따라 인센티브가 차등 지급됩니다. 이때, 두 점수의 합이 동일한 사원들은 동석차이며, 동석차의 수만큼 다음 석차는 건너 뜁니다. 예를 들어 점수의 합이 가장 큰 사원이 2명이라면 1등이 2명이고 2등 없이 다음 석차는 3등부터입니다.

각 사원의 근무 태도 점수와 동료 평가 점수 목록 scores이 주어졌을 때, 완호의 석차를 return 하도록 solution 함수를 완성해주세요.

 

입출력( + 추가적인 Test Case)


scores result
[[2,2],[1,4],[3,2],[3,2],[2,1]] 4
[[4,3],[5,5],[4,4],[2,2],[6,0]] -1
[[9,0],[5,5],[6,6]] 2

제한사항


더보기
  • 1 ≤ scores의 길이 ≤ 100,000
  • scores의 각 행은 한 사원의 근무 태도 점수와 동료 평가 점수를 나타내며 [a, b] 형태입니다.
    • scores[0]은 완호의 점수입니다.
    • 0 ≤ a, b ≤ 100,000
  • 완호가 인센티브를 받지 못하는 경우 -1을 return 합니다.

풀이방법


1. 완호의 점수를 저장해놓습니다.

2. 점수를 근무 태도 점수는 내림차순, 동료 평가 점수는 오름차순으로 정렬합니다.

3. 현재 점수가 완호의 점수보다 모두 크다면 -1을 반환합니다.

4. limit > score[1]인 경우, incentive를 받지 못하는 사람이므로 다음 차례로 넘어갑니다.

5. limit <= score[1]인 경우, incentive를 받는 사람이므로 완호의 점수의 총합과 비교해서 등수를 계산합니다.

6. limit을 갱신합니다.

7. 비교가 끝나면 등수를 반환합니다.

 

* limit > score[1]일 때, incentive를 받지 못하는 이유에 대해 설명해보겠습니다.

limit은 이전 수들 중에서 가장 큰 동료 평가 점수(score[1])입니다.

현재 동료 평가 점수(socre[1])가 limit 보다 작다면, 동료의 인사고과 점수보다 낮은 것을 알 수 있습니다.

현재 근무 태도 점수(socre[0])은 내림차순입니다. 다시 말한다면, 이전 동료의 근무 태도 점수가 더 높다는 것입니다.

다시말해서, score[0], score[1] 모두 동료의 점수보다 낮다는 것을 알 수 있습니다.

 

 

 

 

코드


def solution(scores):
    answer = 1
    wanho_score = scores[0]
    sum_wanho_score = sum(scores[0])
    scores.sort(key=lambda x: (-x[0], x[1]))
    limit = 0

    for score in scores:
        sum_score = sum(score)
        if wanho_score[0] < score[0] and wanho_score[1] < score[1]:
            return -1

        # limit > score[1] 은 incentive를 받지 못하는 사람이다.
        if limit <= score[1]:

            # 성립한다는 것은 인센티브를 받는 것이므로 숫자를 계산해서 등수를 계산한다.
            if sum_wanho_score < sum_score:
                answer += 1
            limit = score[1]
    return answer

 

결론


처음에 문제를 잘못 해석해 시간이 오래 걸렸다. 10번 줄에 max(wanho_score) < min(score)인 경우로 계산했는데 이 것은 틀린 풀이이다. 두 값 중 min과 max를 구하는 것이 아닌 각각의 요소의 대소관계를 계산했어야 했다. 그 이후 오름차순과 내림차순을 떠올리지 못해서 다른 분들의 코드를 참고해서 문제를 풀었다. Level 3으로 와서 그런지 문제가 상당히 어렵다.

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/160585

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제


더보기

틱택토는 두 사람이 하는 게임으로 처음에 3x3의 빈칸으로 이루어진 게임판에 선공이 "O", 후공이 "X"를 번갈아가면서 빈칸에 표시하는 게임입니다. 가로, 세로, 대각선으로 3개가 같은 표시가 만들어지면 같은 표시를 만든 사람이 승리하고 게임이 종료되며 9칸이 모두 차서 더 이상 표시를 할 수 없는 경우에는 무승부로 게임이 종료됩니다.

할 일이 없어 한가한 머쓱이는 두 사람이 하는 게임인 틱택토를 다음과 같이 혼자서 하려고 합니다.

  • 혼자서 선공과 후공을 둘 다 맡는다.
  • 틱택토 게임을 시작한 후 "O"와 "X"를 혼자서 번갈아 가면서 표시를 하면서 진행한다.

틱택토는 단순한 규칙으로 게임이 금방 끝나기에 머쓱이는 한 게임이 종료되면 다시 3x3 빈칸을 그린 뒤 다시 게임을 반복했습니다. 그렇게 틱택토 수 십 판을 했더니 머쓱이는 게임 도중에 다음과 같이 규칙을 어기는 실수를 했을 수도 있습니다.

  • "O"를 표시할 차례인데 "X"를 표시하거나 반대로 "X"를 표시할 차례인데 "O"를 표시한다.
  • 선공이나 후공이 승리해서 게임이 종료되었음에도 그 게임을 진행한다.

게임 도중 게임판을 본 어느 순간 머쓱이는 본인이 실수를 했는지 의문이 생겼습니다. 혼자서 틱택토를 했기에 게임하는 과정을 지켜본 사람이 없어 이를 알 수는 없습니다. 그러나 게임판만 봤을 때 실제로 틱택토 규칙을 지켜서 진행했을 때 나올 수 있는 상황인지는 판단할 수 있을 것 같고 문제가 없다면 게임을 이어서 하려고 합니다.

머쓱이가 혼자서 게임을 진행하다 의문이 생긴 틱택토 게임판의 정보를 담고 있는 문자열 배열 board가 매개변수로 주어질 때, 이 게임판이 규칙을 지켜서 틱택토를 진행했을 때 나올 수 있는 게임 상황이면 1을 아니라면 0을 return 하는 solution 함수를 작성해 주세요.

 

입출력( + 추가적인 Test Case)


board result
["O.X", ".O.", "..X"] 1
["OOO", "...", "XXX"] 0
["...", ".X.", "..."] 0
["...", "...", "..."] 1
["OXX",".OX","..O"] 1
["OXX","OXX","OOO"] 0
["O.X","OOX",".OX"] 0

제한사항


더보기
  • board의 길이 = board[i]의 길이 = 3
    • board의 원소는 모두 "O", "X", "."으로만 이루어져 있습니다.
  • board[i][j]는 i + 1행 j + 1열에 해당하는 칸의 상태를 나타냅니다.
    • "."은 빈칸을, "O"와 "X"는 해당 문자로 칸이 표시되어 있다는 의미입니다.

풀이방법


틱택토가 성립이 안되는 경우가 있습니다.

1. 순서가 어긋난 경우

2. X가 성립되고 O를 놓는 경우

3. O가 성립되고 X를 놓는 경우

총 3가지가 있습니다.

 

1번의 경우

O의 개수는 cnt_o, X의 개수는 cnt_X 입니다.

cnt_x > cnt_o 의 경우

cnt_o > cnt_x + 1 의 경우 2가지 중 하나라도 성립되는 경우 오류입니다.

 

tic_o는 O가 성립된 경우, tic_x는 X가 성립된 경우 입니다.

 

2번의 경우

tic_x == 1 이면서 cnt_o > cnt_x 이면, X가 성립되고 O를 놓은 경우이므로 오류입니다.

 

3번의 경우

tic_o == 1 이면서 cnt_o == cnt_x 이면, O가 성립되고, X를 놓는 경우이므로 오류입니다.

 

총 3가지의 경우를 거치고 오류가 없다면 틱택토는 성립합니다.

코드


def tic_tac_toe(player, board):
    tic = 0

    for i in range(3):
        if all(player == cell for cell in board[i]):
            tic += 1

    for j in range(3):
        if all(player == board[i][j] for i in range(3)):
            tic += 1

    if all(board[i][i] == player for i in range(3)):
        tic += 1
    if all(board[i][2 - i] == player for i in range(3)):
        tic += 1

    return tic


def solution(board):
    board_list = [list(i) for i in board]

    # x, o 개수 세기
    cnt_x, cnt_o = 0, 0
    for i in range(3):
        for j in range(3):
            if board_list[i][j] == 'X':
                cnt_x += 1
            elif board_list[i][j] == 'O':
                cnt_o += 1
            else:
                continue

    # 순서가 어긋난 경우
    if cnt_x > cnt_o or cnt_o > cnt_x + 1:
        return 0
        
	# x와 o의 틱택토 성립하는지 확인
    tic_o = tic_tac_toe('O', board)
    tic_x = tic_tac_toe('X', board)

    # o 가 완성된 이후 x를 놓은 경우
    if tic_o == 1 and (cnt_x == cnt_o):
        return 0

    # x 가 완성된 이후 o를 놓은 경우
    if tic_x == 1 and (cnt_o > cnt_x):
        return 0

    return 1

 

all functions을 사용하지 않은 경우

더보기
def tic_tac_toe(board_list):
    tic_o = 0
    if board_list[0] == ['O', 'O', 'O'] or board_list[1] == ['O', 'O', 'O'] or board_list[2] == ['O', 'O', 'O']:
        tic_o += 1

    if board_list[0][0] == 'O' and board_list[1][0] == 'O' and board_list[2][0] == 'O':
        tic_o += 1
    elif board_list[0][1] == 'O' and board_list[1][1] == 'O' and board_list[2][1] == 'O':
        tic_o += 1
    elif board_list[0][2] == 'O' and board_list[1][2] == 'O' and board_list[2][2] == 'O':
        tic_o += 1

    if board_list[0][0] == 'O' and board_list[1][1] == 'O' and board_list[2][2] == 'O':
        tic_o += 1
    elif board_list[0][2] == 'O' and board_list[1][1] == 'O' and board_list[2][0] == 'O':
        tic_o += 1

    tic_x = 0
    if board_list[0] == ['X', 'X', 'X'] or board_list[1] == ['X', 'X', 'X'] or board_list[2] == ['X', 'X', 'X']:
        tic_x += 1

    if board_list[0][0] == 'X' and board_list[1][0] == 'X' and board_list[2][0] == 'X':
        tic_x += 1
    elif board_list[0][1] == 'X' and board_list[1][1] == 'X' and board_list[2][1] == 'X':
        tic_x += 1
    elif board_list[0][2] == 'X' and board_list[1][2] == 'X' and board_list[2][2] == 'X':
        tic_x += 1

    if board_list[0][0] == 'X' and board_list[1][1] == 'X' and board_list[2][2] == 'X':
        tic_x += 1
    elif board_list[0][2] == 'X' and board_list[1][1] == 'X' and board_list[2][0] == 'X':
        tic_x += 1

    return tic_o, tic_x


def solution(board):
    board_list = [list(i) for i in board]

    # x, o 개수 세기
    cnt_x, cnt_o = 0, 0
    for i in range(3):
        for j in range(3):
            if board_list[i][j] == 'X':
                cnt_x += 1
            elif board_list[i][j] == 'O':
                cnt_o += 1
            else:
                continue

    # 순서가 어긋난 경우
    if cnt_x > cnt_o or cnt_o > cnt_x + 1:
        return 0

    tic_o, tic_x = tic_tac_toe(board_list)

    # o 가 완성되었는데 x를 놓은 경우
    if tic_o == 1 and (cnt_x == cnt_o):
        return 0

    # x 가 완성되었는데 o를 놓은 경우
    if tic_x == 1 and (cnt_o > cnt_x):
        return 0

    answer = 1
    return answer

상당히 코드가 더럽다. all function을 사용해서 깔끔하게 바꾸었다. 

 

결론


처음에 규칙을 찾느라 어려웠다. 틱택토를 해본적도 없었기 때문이다. 규칙을 빨리 찾고나서 구현은 생각보다 쉬웠다. 하지만 밑에 있는 코드는 너무 복잡해 보여서 Python의 all function을 사용해서 깔끔하게 바꾸었다. 덕분에 all function을 배워갔다.

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/159993

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제


1 x 1 크기의 칸들로 이루어진 직사각형 격자 형태의 미로에서 탈출하려고 합니다. 각 칸은 통로 또는 벽으로 구성되어 있으며, 벽으로 된 칸은 지나갈 수 없고 통로로 된 칸으로만 이동할 수 있습니다. 통로들 중 한 칸에는 미로를 빠져나가는 문이 있는데, 이 문은 레버를 당겨서만 열 수 있습니다. 레버 또한 통로들 중 한 칸에 있습니다. 따라서, 출발 지점에서 먼저 레버가 있는 칸으로 이동하여 레버를 당긴 후 미로를 빠져나가는 문이 있는 칸으로 이동하면 됩니다. 이때 아직 레버를 당기지 않았더라도 출구가 있는 칸을 지나갈 수 있습니다. 미로에서 한 칸을 이동하는데 1초가 걸린다고 할 때, 최대한 빠르게 미로를 빠져나가는데 걸리는 시간을 구하려 합니다.

미로를 나타낸 문자열 배열 maps가 매개변수로 주어질 때, 미로를 탈출하는데 필요한 최소 시간을 return 하는 solution 함수를 완성해주세요. 만약, 탈출할 수 없다면 -1을 return 해주세요.

 

입출력( + 추가적인 Test Case)


maps result
["SOOOL","XXXXO","OOOOO","OXXXX","OOOOE"] 16
["LOOXS","OOOOX","OOOOO","OOOOO","EOOOO"] -1

제한사항에 대해 보고싶으면 눌러주세요

더보기

제한사항


  • 5 ≤ maps의 길이 ≤ 100
    • 5 ≤ maps[i]의 길이 ≤ 100
    • maps[i]는 다음 5개의 문자들로만 이루어져 있습니다.
      • S : 시작 지점
      • E : 출구
      • L : 레버
      • O : 통로
      • X : 벽
    • 시작 지점과 출구, 레버는 항상 다른 곳에 존재하며 한 개씩만 존재합니다.
    • 출구는 레버가 당겨지지 않아도 지나갈 수 있으며, 모든 통로, 출구, 레버, 시작점은 여러 번 지나갈 수 있습니다.

풀이방법


사용한 알고리즘 : BFS

 

크게 2개로 나누어서 구현했습니다.

1. S 에서 L까지의 최단거리를 구합니다.

2. L 에서 E까지의 최단거리를 구합니다.

-> 최단거리를 구하는 방식은 BFS를 사용해서 풀었습니다.

 

코드


from collections import deque

INF = float('inf')

def solution(maps):
    answer = 0
    n = len(maps)
    m = len(maps[0])
    matrix = [[INF] * m for _ in range(n)]
    deq = deque()
    
    # S 위치 찾기
    for i in range(n):
        for j in range(m):
            if maps[i][j] == 'S':
                matrix[i][j] = 0
                deq.append((i, j, 0))
                break
        if deq:
            break

    dx = [0, 0, -1, 1]
    dy = [-1, 1, 0, 0]

    # S => L
    while deq:
        x, y, cnt = deq.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if 0 <= nx < n and 0 <= ny < m and maps[nx][ny] != 'X':
            
            	# L을 찾았을 경우
                if maps[nx][ny] == 'L':
                    answer += cnt + 1

                    # deq 초기화
                    deq = deque()
                    deq.append((nx, ny, 0))
                    break
                    
                if cnt + 1 < matrix[nx][ny]:
                    matrix[nx][ny] = cnt + 1
                    deq.append((nx, ny, cnt + 1))
        if answer != 0:
            break

    temp_answer = answer
    matrix = [[INF] * m for _ in range(n)]

    # L => E
    
    while deq:
        x, y, cnt = deq.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if 0 <= nx < n and 0 <= ny < m and maps[nx][ny] != 'X':
                if maps[nx][ny] == 'E':
                    answer += cnt + 1
                    break
                if cnt + 1 < matrix[nx][ny]:
                    matrix[nx][ny] = cnt + 1
                    deq.append((nx, ny, cnt + 1))
        
        # answer 값이 변하면 break
        if answer != temp_answer:
            break

	# L -> E 경로가 없으면 -1
    if answer == temp_answer:
        return -1

    return answer

 

결론


1. S 에서 L까지의 최단거리를 구합니다.

2. L 에서 E까지의 최단거리를 구합니다.

 

1에서 최단거리가 없을 경우, 2에서 최단거리가 없는 경우와 둘 다 없는 경우를 생각해서 풀면 바로 풀리는 문제이다. 단, 범위오류가 발생할 수 있으니 변수 설정을 잘 해주면 된다.

 

처음 겪어보는 런타임 에러여서 당황했지만 백준에서 해왔던 것처럼 범위 오류라 가정하고 변수를 재설정하여 해결하였다.

 

 

 

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/176962

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제


과제를 받은 루는 다음과 같은 순서대로 과제를 하려고 계획을 세웠습니다. 
  과제는 시작하기로 한 시각이 되면 시작합니다.
  새로운 과제를 시작할 시각이 되었을 때, 기존에 진행 중이던 과제가 있다면 진행 중이던 과제를 멈추고 새로운 과제를 시작합니다.

  진행중이던 과제를 끝냈을 때, 잠시 멈춘 과제가 있다면, 멈춰둔 과제를 이어서 진행합니다.

    만약, 과제를 끝낸 시각에 새로 시작해야 되는 과제와 잠시 멈춰둔 과제가 모두 있다면, 새로 시작해야 하는 과제부터 진행합니다.

  멈춰둔 과제가 여러 개일 경우, 가장 최근에 멈춘 과제부터 시작합니다.

과제 계획을 담은 이차원 문자열 배열 plans가 매개변수로 주어질 때, 과제를 끝낸 순서대로 이름을 배열에 담아 return 하는 solution 함수를 완성해주세요.

입출력 ( + 추가적인 Test Case)


plans result
[["korean", "11:40", "30"], ["english", "12:10", "20"], ["math", "12:30", "40"]] ["korean", "english", "math"]
[["science", "12:40", "50"], ["music", "12:20", "40"], ["history", "14:00", "30"], ["computer", "12:30", "100"]] ["science", "history", "computer", "music"]
[["aaa", "12:00", "20"], ["bbb", "12:10", "30"], ["ccc", "12:40", "10"]] ["bbb", "ccc", "aaa"]
[["d", "11:00", "30"], ["f", "11:10", "30"], ["g", "14:00", "30"]] ["f", "d", "g"]
[['A', "12:00", "30"], ['B', "12:10", "20"], ['C', "15:00", "40"], ['D', "15:10", "30"]] ["B", "A", "D", "C"]

 

더보기

제한사항


3 ≤ plans의 길이 ≤ 1,000 
  plans의 원소는 [name, start, playtime]의 구조로 이루어져 있습니다. 
    name : 과제의 이름을 의미합니다. 
      2 ≤ name의 길이 ≤ 10 name은 알파벳 소문자로만 이루어져 있습니다. 
      name이 중복되는 원소는 없습니다. 
    start : 과제의 시작 시각을 나타냅니다. 
      "hh:mm"의 형태로 "00:00" ~ "23:59" 사이의 시간값만 들어가 있습니다. 
      모든 과제의 시작 시각은 달라서 겹칠 일이 없습니다. 
      과제는 "00:00" ... "23:59" 순으로 시작하면 됩니다. 즉, 시와 분의 값이 작을수록 더 빨리 시작한 과제입니다. 
    playtime : 과제를 마치는데 걸리는 시간을 의미하며, 단위는 분입니다. 
      1 ≤ playtime ≤ 100 
      playtime은 0으로 시작하지 않습니다. 
  

배열은 시간순으로 정렬되어 있지 않을 수 있습니다.
진행중이던 과제가 끝나는 시각과 새로운 과제를 시작해야하는 시각이 같은 경우 진행중이던 과제는 끝난 것으로 판단합니다.

 

풀이방법


시간 순서대로 풀어 내기 위해서 hh:mm 형식을 -> 분 형식으로 바꾸는 함수를 만들었습니다.  ex) 12:30 -> 750

1. plans의 내부 요소 중에 time을 함수를 이용해 hh:mm 형식을 total_time인 정수형태로 바꾸어서 다시 저장했습니다.

2. plans에서의 total_time을 작은 순부터 정렬했습니다.

3. plans의 가장 앞에 있는 total_time을 now_time으로 설정하고 과제 풀이를 시작했습니다.

* first와 second의 설명 : second는 현재 처리 해야할 과제를 가리킵니다. first는 현재 처리할 과제보다 앞에 있는 과제들을 가리킵니다.

* stack을 통해서 stack은 현재 처리해야할 과제 이전에 과제들을 담아두는 장소입니다.

4. stack이 비어있는 경우, 현재 과제와 처리되지 않은 이전 과제들을 비교할 수 없어서 stack에 현재 과제를 추가합니다.

5. stack이 비어있지 않은 경우,

5-1. 현재 과제가 다음 과제 시작시간보다 이전에 끝나는 경우, answer 에 추가합니다.

5-2. 현재 과제가 다음 과제 시작시간을 넘어가는 경우, plans에 다음과제를 처리합니다.

6. plans를 다 순회하게 된다면 남은 과제들을 차례대로 stack 방식으로 answer에 처리되지 않은 과제들을 추가합니다.

7. answer을 반환합니다.

코드


from collections import deque


# 시간 계산
def cal_time(time):
    total_time = 0
    hour, minute = map(int, time.split(':'))
    total_time = hour * 60 + minute
    return total_time


def solution(plans):
    answer = []
    plans = [(name, cal_time(time), int(playtime)) for name, time, playtime in plans]
    # 시작시간 순으로 정렬
    plans.sort(key=lambda x: x[1])
    stack = deque()

	# 시작시간 설정
    now_time = plans[0][1]

    for i in plans:
        second_name, second_time, second_playtime = i

        while stack:
            first_name, first_playtime = stack.pop()
            # 진행중인 과제를 끝낸 경우
            if now_time + first_playtime <= second_time:
                now_time = now_time + first_playtime
                answer.append(first_name)
            # 과제를 끝내지 못하고 다음 과제가 오는 경우
            else:
                stack.append((first_name, (now_time + first_playtime) - second_time))
                now_time = second_time
                break

        stack.append((second_name, second_playtime))
        # 과제가 끝나고 다음 과제 시간으로 설정
        now_time = second_time

	# 미뤄뒀던 과제들 차례대로 마침
    while len(stack) != 0:
        answer.append(stack.pop()[0])

    return answer

결론


stack 방식을 사용해서 풀면된다.

39번째 줄에 있는 코드를 사용하지 않는다면, 2,3,4,5,7 번 case를 틀렸다. 시간 설정을 좀 더 유의해서 할 필요가 있다.

오류가 발생하는 이유는 현재 과제를 처리하고 다음 과제를 처리하기 전까지 시간이 비어있다면 시간 설정에서 오류가 발생했다.

 

728x90
728x90

 

deque 이란?


결론부터 말씀드리자면 list 와 같은 배열이지만 "양쪽에서 요소를 추가와 삭제가 가능한" 자료구조입니다.

 

Python의 collections 모듈에서 제공하는 deque는 "double-ended queue"(양방향 큐)의 줄임말 입니다. 다시 말해서 queue(큐)에 앞쪽에 연산이 추가된 자료구조라고 볼 수 있습니다.

 

써야하는 이유


deque 자료구조는 pop, append method는 시간복잡도가 O(1)입니다.


하지만 list 자료구조에서 pop, append method는 시간복잡도가 O(n)입니다.

이러한 이유로 작은 데이터 셋에서는 큰 차이가 없지만 데이터 셋이 큰 경우에 큰 차이를 알 수 있습니다.

특히 BFS를 queue로 구현하면 시간초과가 발생하지만 deque를 통해 구현하면 시간초과가 발생하지 않습니다.

 

그러므로 간단하거나 작은 데이터의 경우에는 list, 그 외의 경우에는 deque를 사용하는 것을 추천합니다.

 

메소드 종류


import collections

d = collections.deque()

 

메소드 설명
d.append(item) 덱의 오른쪽에 요소(item)을 추가합니다.
d.appendleft(item) 덱의 왼쪽에 요소(item)을 추가합니다.
d.pop() 덱의 오른쪽에 요소(item)을 제거하면서 반환합니다.
d.popleft() 덱의 왼쪽에 요소(item)을 제거하면서 반환합니다.
d.extend(array) 덱의 오른쪽에 array를 추가합니다.
d.extendleft(array) 덱의 왼쪽에 array를 "뒤집어서" 추가합니다.
d.rotate(n) 덱을 양수면 n 만큼 오른쪽으로, 음수면 n 만큼 왼쪽으로 회전합니다.

 

구현 방법


 

from collections import deque
d = deque('ghi')                 # 'g', 'h' 'i' 요소를 가진 deque 생성합니다.
for elem in d:                   # deque 요소를 순회하며 출력합니다.
    print(elem.upper())
    
# 출력결과
# G
# H
# I 

d.append('j')                    		# 오른쪽에 'j'를 추가합니다.
d.appendleft('f')                		# 왼쪽에 'f'를 추가합니다.
print(d)                         		# deque 출력합니다.
# deque(['f', 'g', 'h', 'i', 'j'])

print(d.pop())                          # 오른쪽 요소를 제거 및 반환되면서 출력합니다.
# j
print(d.popleft())                      # 왼쪽 요소를 제거 및 반환되면서 출력합니다.
# f
print(list(d))                          # deque의 요소를 모두 출력합니다.
# ['g', 'h', 'i']
print(d[0])                             # 왼쪽의 첫번재 요소 출력합니다.
# g
print(d[-1])                            # 오른쪽의 첫번째 요소 출력합니다.
# i

print(list(reversed(d)))                # deque의 요소를 반전합니다.
# ['i', 'h', 'g']
print('h' in d)                         # deque안에 요소 찾기합니다.
# True
d.extend('jkl')                  		# 오른쪽에 array를 추가합니다.
print(d)
# deque(['g', 'h', 'i', 'j', 'k', 'l'])
d.rotate(1)                      		# 오른쪽으로 1만큼 회전합니다.
print(d)
# deque(['l', 'g', 'h', 'i', 'j', 'k'])
d.rotate(-1)		                     # 왼쪽으로 1만큼 회전합니다.
print(d)
# deque(['g', 'h', 'i', 'j', 'k', 'l'])

print(deque(reversed(d)))               # deque를 반전시킵니다.
# deque(['l', 'k', 'j', 'i', 'h', 'g'])
d.clear()                        		# deque의 요소들을 모두 제거합니다.
d.pop()                          		# deque의 요소들이 없어서 오류를 발생시킵니다.
# 오류출력
# Traceback (most recent call last):
#    File "<pyshell#6>", line 1, in -toplevel-
#        d.pop()
# IndexError: pop from an empty deque

d.extendleft('abc')              # c -> b -> a 순으로 왼쪽에 추가하기 때문에 뒤집에서 추가됩니다.
print(d)
# deque(['c', 'b', 'a'])

 

관련문제들


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

 

10845번: 큐

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지

www.acmicpc.net

list와 deque를 모두 구현해볼 수 있는 문제입니다.

 

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

 

7569번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100,

www.acmicpc.net

list로 구현하면 시간초과가 발생하고 deque로 구현하면 시간초과가 발생하지 않는 문제입니다.

 

 

참고문헌 : https://docs.python.org/ko/3/library/collections.html#collections.deque

 

728x90