프로그래머스 스택/큐

# 다리를 지나는 트럭 (Level2)

  • 앞 쪽에 위치한 트럭이 우선적으로 다리를 건너야 하기 때문에 FIFO 구조
  • 리스트의 pop(0)은 0(n)의 시간복잡도를 가지고 deque의 popleft()는 O(1)의 시간복잡도를 가지기 때문에 deque사용한다
  • 1초가 지날때마다 현재 다리에 있는 트럭의 무게와 다음으로 올라갈 트럭의 무게의 합이 최대 하중을 넘는지 확인한다
  • 하중을 넘지 않는다면 다음 트럭을 올리고
  • 그렇지 않다면 0을 더해 다리를 왼쪽으로 밀어낸다

 

- 첫번째 풀이(실패)

  • Point. 하나의 테스트케이스에서 시간초과가 났다 -> sum이 O(n)이라 시간초과 발생

 

from collections import deque
def solution(bridge_length, weight, truck_weights):
    time = 0
    truck_q = deque(truck_weights)
    q = deque([0] * bridge_length)
    
    while q:
        time += 1
        q.popleft()
        if truck_q:
            if sum(q) + truck_q[0] <= weight:
                q.append(truck_q.popleft())
            else:
                q.append(0)
    
    return time

 

- 두번째 풀이 (성공) -> sum대신 다리의 무게를 따로 관리해준다

from collections import deque
def solution(bridge_length, weight, truck_weights):
    time = 0
    truck_q = deque(truck_weights)
    q = deque([0] * bridge_length)
    t_weight = 0 # 현재 다리의 무게
    
    while q:
        time += 1
        # 나갈 트럭이 있다면 그 무게를 빼준다
        if q[0] != 0: t_weight -= q[0]
        q.popleft()
        if truck_q:
            # 다리의 무게와 대기하는 트럭의 크기가 weight값을 넘지 않으면 더해준다
            if t_weight + truck_q[0] <= weight:
                t_weight += truck_q[0]
                q.append(truck_q.popleft())
            else:
                q.append(0)

    return time

 

* 시간복잡도를 생각하는 습관을 길러야겠다

wiki.python.org/moin/TimeComplexity

 

TimeComplexity - Python Wiki

This page documents the time-complexity (aka "Big O" or "Big Oh") of various operations in current CPython. Other Python implementations (or older or still-under development versions of CPython) may have slightly different performance characteristics. Howe

wiki.python.org

 

반응형

프로그래머스 스택/큐

# 프린터

- 나의 풀이

  • 순서를 표시할 deque와 순서에 해당하는 중요도값을 저장한 dic값을 만들어줌
  • 맨 앞 대기목록의 중요도와 나머지 중요도를 비교해 중요도가 가장 높으면 출력을 아니면 뒤로 빼준다 -> deque를 써야하는 이유 앞뒤로 빠져야되니까
from collections import deque
def solution(priorities, location):
    answer = 0
    queue = deque(i for i in range(len(priorities)))
    dic = {}
    
    for i in range(len(priorities)):
        dic[i] = priorities[i]
    
    while queue:
        tmp = queue.popleft()
        dic_value = list(dic.values())
        if dic[tmp] == max(dic_value):
            del dic[tmp]
            answer+=1
            if tmp == location:
                break
        else:
            queue.append(tmp)
        
    return answer

 

+ (GOOD) 풀이

  • deque에 중요도와 순서를 함께 저장함
from collections import deque
def solution(priorities, location):
    answer = 0
    # v : 중요도 , i : 순서
    queue = deque((v,i) for i,v in enumerate(priorities))
    
    while queue:
        item = queue.popleft()
        if item[0] < max(queue)[0]:
            queue.append(item)
        else:
            answer+=1
            if item[1] == location:
                break
        
    return answer

 

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

def solution(n):
    answer = []
    for i in str(n):
        answer.append(int(i))
    answer.reverse()
    return answer
    #return list(map(int, reversed(str(n))))

 

# 나누어 떨어지는 숫자 배열

def solution(arr, divisor):
    answer = []
    for i in arr:
        if i%divisor == 0:
            answer.append(i)
    
    if len(answer) == 0:
        answer = [-1]
    else:
        answer.sort()
    return answer
반응형

# 시저 암호

def solution(s, n):
    answer = ''
    alpa = 'abcdefghijklmnopqrstuvwxyz'
    Alpa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    for i in s:
        if i in alpa:
            answer += alpa[(alpa.index(i)+n)%26]
        elif i in Alpa:
            answer += Alpa[(Alpa.index(i)+n)%26]
        else:
            answer += " "
            
    return answer

 

# 콜라츠 추측

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

 

# 하샤드 수

def solution(x):
    answer = True
    x_sum = sum(int(i) for i in str(x))
        
    if x % x_sum != 0:
        answer = False

    return answer

 

# 제일 작은 수 제거하기

def solution(arr):
    answer = []
    arr.remove(min(arr))
    if len(arr)==0:
        answer = [-1]
    else:
        answer = arr
    return answer

 

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

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

 

# 평균 구하기

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

 

# 짝수와 홀수

def solution(num):
    answer = ''
    if num%2 == 0:
        answer = "Even"
    else:
        answer =  "Odd"
    return answer

 

# 핸드폰 번호 가리기

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

 

# 직사각형 별찍기

a, b = map(int, input().strip().split(' '))
for i in range(b):
    print('*'*a)

 

반응형

프로그래머스 - 깊이/너비 우선 탐색(DFS/BFS)

# 여행경로 (Level 3)

 

  • Point . dic로 그래프 만들고 DFS로 풀기
from collections import defaultdict
def solution(tickets):
    # 특정 티켓의 인접 리스트를 구하는 함수
    def init_graph():
        routes = defaultdict(list)
        for key, value in tickets:
            routes[key].append(value)
        return routes

    # 스택을 사용한 DFS
    def dfs():
        stack = ["ICN"] # 첫시작은 ICN
        path = []  # 가려고하는 경로를 저장하는 변수
        while stack:  # stack이 비어있을 때까지
            top = stack[-1]
            # 특정 공항에서 출발하는 표가 없다면 또는 있지만 티켓을 다 써버린 경우
            if top not in routes or len(routes[top]) == 0:
                path.append(stack.pop())
            else:
                stack.append(routes[top].pop(0))
        return path[::-1]

    routes = init_graph() # 그래프로 만들기
    for r in routes: # 알파벳순 정렬
        routes[r].sort() 
    answer = dfs() # 경로 구하기
    
    return answer
반응형

DFS나 BFS를 풀 때 그래프를 만들어 풀면 수월한 문제들이 있다

예를 들어 ( 프로그래머스 여행경로 문제  )

 

코딩테스트 연습 - 여행경로

[["ICN", "SFO"], ["ICN", "ATL"], ["SFO", "ATL"], ["ATL", "ICN"], ["ATL","SFO"]] ["ICN", "ATL", "ICN", "SFO", "ATL", "SFO"]

programmers.co.kr

  • 항공권 정보가 담긴 2차원 배열 tickets가 매개변수로 주어질 때
  • tickets의 각 행 [a, b]는 a 공항에서 b 공항으로 가는 항공권이 있다는 의미이다
[["ICN", "SFO"], 
["ICN", "ATL"], 
["SFO", "ATL"], 
["ATL", "ICN"], 
["ATL","SFO"]]

 

이를 딕셔너리를 사용하여 그래프를 만들면

  • 첫 번째 방법
routes = {}
for key, value in tickets:
	if key in routes:
		routes[key].append(value)
	else:
		routes[key] = [value]

>>> {'ICN': ['SFO', 'ATL'], 'SFO': ['ATL'], 'ATL': ['ICN', 'SFO']}

 

  • defaultdict()를 활용한 이보다 간편한 두 번째 방법 -> 키가 있는지 확인할 필요가 없다
from collections import defaultdict

routes = defaultdict(list)
for key, value in tickets:
	routes[key].append(value)
   
>>> defaultdict(<class 'list'>, {'ICN': ['SFO', 'ATL'], 'SFO': ['ATL'], 'ATL': ['ICN', 'SFO']})

 

 

+ defaultdict() 활용법

  • defaultdict()는 인자로 주어진 객체의 기본값을 딕셔너리 값의 초기값으로 지정할 수 있다.
  • 숫자, 리스트, 셋 등으로 초기화 할 수 있다.
  • 외부 함수이기 때문에 import 해야 됨 -> from collections import defaultdict
  1. 숫자로 초기화 -> 값을 지정하지 않으면 0으로 초기화 ex) 알파벳 횟수 계산
  2. 리스트로 초기화 -> 값을 지정하지 않으면 빈 리스트로 초기화 ex) 그래프 경로, 같은 성을 가진 이름끼리 취합하기 
  3. 셋으로 초기화 -> 값을 지정하지 않으면 빈 리스트로 초기화
# 1번 숫자로 초기화

from collections import defaultdict
int_dict = defaultdict(int)
int_dict
>>> defaultdict(<class 'int'>, {}) # 디폴트값이 int인 딕셔너리

# 값 지정 안하면 0으로 초기화
int_dict['key1']
>>> 0
int_dict
>>> defaultdict(<class 'int'>, {'key1': 0}) 

# 값 지정하면 그 값으로 지정
int_dict['key2'] = 'test'
int_dict
>>> defaultdict(<class 'int'>, {'key1': 0, 'key2': 'test'}) 
# 리스트로 초기화

from collections import defaultdict
list_dict = defaultdict(list)
list_dict
>>> defaultdict(<class 'list'>, {}) # 디폴트값이 list인 딕셔너리

list_dict['key1'] # 값을 지정하지 않으면 빈 리스트로 초기화
>>> []

list_dict['key2'] = 'test' # 값을 지정하면 해당값으로 초기화
list_dict
>>> defaultdict(<class 'list'>, {'key1': [], 'key2': 'test'}) 

( 참고 : 유사 딕셔너리 defaultdict() 활용법 )

반응형

프로그래머스 - 깊이/너비 우선 탐색(DFS/BFS)

# 단어 변환 (Level 3)

  • Point. 그래프 문제인 이유 : 한 개의 알파벳만 달라 다음에 올 수 있는 단어를 방문하여 target값을 찾는다
  • 방문한(pop)한 원소 temp가 방문할 수 있는 값은 temp와 한 개의 알파벳만 다른 words 원소 값이다.
from collections import deque
def solution(begin, target, words):
    answer = 0 # 변환할 수 없는 경우 0 return
    queue = deque()

    for i in words: # 한 개의 알파벳만 다를 경우
        count = 0
        for j in range(len(begin)):
            if begin[j] != i[j]:
                count+=1
        if count == 1:
            queue.append([i,0]) 
            words.remove(i)
    
    while queue: 
        temp, idx = queue.popleft() 
        idx += 1
        if temp == target: # 변환이 가능한 경우 몇단계인지 저장
            answer = idx
        else:
            for i in words:
                count = 0
                for j in range(len(begin)):
                    if temp[j] != i[j]:
                        count+=1
                if count == 1:
                    queue.append([i,idx])
                    words.remove(i)
                    
    return answer

 

# 문자열을 정수로 바꾸기 

def solution(s):
    return int(s)

 

# 자릿수 더하기

  • Point. 문자열로 변환해 한자리씩 들고온 후, 다시 정수형으로 변환해 더해준다
def solution(n):
    answer = 0
    for i in str(n):
        answer+=int(i)

    return answer

 

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

  • Tip. 리스트 합쳐서 하나의 문자열로 바꾸는 함수 : '구분자'.join(리스트) 
def solution(n):
    answer = ""
    n_list = list(str(n))
    n_list.sort(reverse=True)
    
    for i in n_list:
        answer+=i
    return int(answer)

    # return int("".join(n_list))
반응형

프로그래머스 - 깊이/너비 우선 탐색(DFS/BFS)

# 타겟 넘버 (Level2) : 2021.04.07 - [알고리즘] - 20210407_코테공부

# 네트워크 (Level 3) : 2021.02.17 - [알고리즘] - 20210217_코테공부

# 단어 변환 (Level 3) : 2021.04.08 - [알고리즘] - 20210408_코테공부

# 여행경로 (Level 3) : 2021.04.12 - [알고리즘] - [ 프로그래머스 / 파이썬 ] 여행경로 - DFS/BFS

 


 

백준

# 17406 배열 돌리기 4 (골드4) : 2021.02.04 - [알고리즘] - 20210204_코테공부

# 12100 2048(Easy) (골드2) : 2021.01.29 - [알고리즘] - 20210129_코테공부

# 16768 Mooyo Mooyo (골드4) : 2021.01.28 - [알고리즘] - 20210128_코테공부

# 1021 유기농 배추 (실버2) : 2021.01.12 - [알고리즘] - 20210112_코테공부

#

 

+ DFS/BFS Tip.

반응형

문자열 빈출 함수

  • 문자 개수 세기 : 문자열.count('s')
  • 특정 문자 찾기 : 문자열.find('s')
    • 없으면 -1 리턴
  • (접두어)특정 문자로 시작하는지 여부 : 문자열.startswith('ho') ( 참고자료 )
  • (접미어)특정 문자로 끝나는지 여부 : 문자열.endswith('h')
    • 문자열 대신 문자열로 이루어진 tuple을 넣을 수도 있다. (※리스트 안됨)
  • 위치 알려주기2 : 문자열.index('s')
    • 주의 : 없으면 오류 뜸
  • 리스트를 문자열로 합치기 : '구분자'.join(리스트)
  • 문자열 쪼개 리스트 만들기 : 문자열.split()
    • 파라미터를 안쓰면 띄어쓰기, 엔터를 구분하여 나눈다
  • 문자열 치환 : 문자열.replace('a','b') # a를 b로 바꾼다
a = 'hobby'

# 문자열에서 특정 문자의 개수를 리턴
s1 = a.count('b')
print(s1)
>>> 2

# 위치 찾기1
s2 = a.find('b')
print(s2)
>>> 2
s3 = a.find('k')
print(s3)
>>> -1

# 특정 문자로 시작하는지 여부 
ss1 = a.startswith('ho')
print(ss1)
>>> True

# 특정 문자로 시작하는 여부 (여러개)
url = "https://www.naver.com"
url_check = ("http","https")
url.startswith(url)
>>> True

# 특정 문자로 끝나는지 여부
ss2 = a.endswith('h')
print(ss2)
>>> False

# 위치 찾기2
s4 = a.index('b')
print(s4)
>>> 2
a.index('k')
>>> 오류

# 리스트 문자로 합치기
b = ['a', 'b', 'c', 'd', '1', '2', '3']
s5 = "".join(b)
print(s5)
>>> abcd123
s6 = "-".join(b)
print(s6)
>>> a-b-c-d-1-2-3

# 문자열 쪼개기
c = "a b c d e f g"
s7 = s.split()
print(s7)
>>> ['a','b','c','d','e','f','g']
d = "aa.bb.cc.dd.ee.ff.gg"
s8 = s.split('.')
print(s8)
>>> ['aa','bb','cc','dd','ee','ff','gg']

 

+ 리스트 원소 추가, 삭제

  • 원소 추가 : 리스트.append(값)
  • 특정 위치에 원소 추가 : 리스트.insert(인덱스, 값)
  • 여러 원소 추가하기 : 리스트.extend(추가할 리스트)
  • 특정 위치의 원소 삭제 : del 리스트[인덱스]
  • 원소 값 삭제 : 리스트.remove(값)
a = [1, 2, 3]

# 원소 추가
a.append(6)
>>> [1, 2, 3, 6]

# 특정 위치에 원소 추가
a.insert(1, 5)
>>> [1, 5, 2, 3, 6]

# 여러 원소 추가하기
a.extend([4,5,6])
>>> [1, 5, 2, 3, 6, 4, 5, 6]

# 특정 위치의 원소 삭제
del a[1]
>>> [1, 2, 3, 6, 4, 5, 6]

# 원소 값 삭제
a.remove(3)
>>> [1, 2, 6, 4, 5, 6]

 

문자열 정렬

  • 리스트로 변환 후 sort, sorted를 사용하여 정렬한다.
    • list 본체 정렬 : 문자열.sort() # reverse = True 시 내림차순 정렬
    • list 정렬된 결과 반환 : sorted(문자열)
    • list 뒤집기 : 문자열.reverse()
    • 관련 문제 : 문자열 내림차순으로 배치하기  2021.04.07 - [알고리즘] - 20210407_코테공부
 

20210407_코테공부

프로그래머스 - 깊이/너비 우선 탐색(DFS/BFS) # 타겟 넘버 (Level 2) Point. 타겟 넘버가 그래프 문제인 이유 -> 다음 인덱스에 해당하는 numbers 원소를 더하거나 빼 값을 방문한다. 방문한(pop)한 원소 temp

jungeun960.tistory.com

s = "Zbcdefg"
s = list(s)
print(s)
>>> ['Z', 'b', 'c', 'd', 'e', 'f', 'g']

s.sort(reverse = True)
print(s)
>>> ['g', 'f', 'e', 'd', 'c', 'b', 'Z']

a = [1, 10, 5, 7, 6]
a.sort()
a
>>> [1, 5, 6, 7, 10]

y = sorted(a)
y
>>> [1, 5, 6, 7, 10]

a.reverse()
a
>>> [6, 7, 5, 10, 1]

+ 문자열의 길이를 기준으로 정렬 : 문자열.sort(key=lamba x:len(x))

+ 문자열의 n번째 수 기준으로 정렬 : 문자열.sort(key=lambda x:x[n])

+ 다중 조건 정렬 : 문자열.sort(key=lambda x: (x[0],x[1])) // x[0] 기준으로 정렬하고 x[1] 기준으로 정렬

a = [(4,0), (4,3), (4,2), (3,2), (2,1), (1,0)]


# 인자 없이 sorted()를 사용하면 리스트 아이템의 각 요소 순서대로 정렬
# 첫 번째 요소가 같으면 두 번째 요소로 비교
b = sorted(a)
print(b)    
>>> [(1, 0), (2, 1), (3, 2), (4, 0), (4, 2), (4, 3)]


# key인자에 lambda 함수를 넘겨주면 반환값을 가지고 비교해 정렬
# 이 때, key로 전달되지 않은 요소에 대해선 정렬하지 않음
c = sorted(a, key=lambda x : x[0])
print(c)    
>>> [(1, 0), (2, 1), (3, 2), (4, 0), (4, 3), (4, 2)]
d = sorted(a, key=lambda x : x[1])
print(d)    
>>> [(4, 0), (1, 0), (2, 1), (4, 2), (3, 2), (4, 3)]


# 정렬 기준으로 다중 조건을 넘겨줄 수도 있다
# 첫 번째 인자를 기준으로 오름차순 정렬을 먼저 한다.
# 그 결과를 가지고 두 번째 인자를 기준으로 내림차순 정렬(-를 붙이면 내림차순 정렬)
e = sorted(a, key = lambda x : (x[0], -x[1]))
print(e)    
>>> [(1, 0), (2, 1), (3, 2), (4, 3), (4, 2), (4, 0)]
 

20210302_코테공부

프로그래머스 # 가운데 글자 가져오기 def solution(s): answer = '' if len(s)%2 == 1: answer = s[len(s)//2] else: answer = s[len(s)//2-1 : len(s)//2+1 ] return answer # 같은 숫자는 싫어 def solution(ar..

jungeun960.tistory.com

 

대소문자 관리 함수 (upper, lower, isupper, islower)

  • 주어진 문자열의 모든 알파벳을 소문자로 바꾸는 함수 : 문자열.lower()
  • 주어진 문자열의 모든 알파벳을 대문자로 바꾸는 함수 : 문자열.upper()
  • 주어진 문자열의 맨 첫 글자를 대문자로 바꾸는 함수 : 문자열.capitalize()
  • 주어지 문자열에서 알파벳 외의 문자(숫자, 특수문자, 띄어쓰기 등)로 나누어져 있는 첫 글자를 모두 대문자로 바꾸는 함수 : 문자열.title()
  • 소문자 확인 : 문자열.islower() -> True / False로 리턴
  • 대문자 확인 : 문자열.isupper() -> True / False로 리턴

※ capitalize()와 title() 차이 주의!

+ 알파벳/숫자인지 확인하기  -> True / False로 리턴

  • 알파벳인지 확인하기 : 문자열.isalpha()
  • 숫자인지 확인하기 : 문자열.isdigit()
  • 알파벳 또는 숫자인지 확인하기 : 문자열.isalnum() -> 특수문자 있는지 확인
  • ※ 문자열에 공백이 포함되어 있으면 False를 리턴합니다

+ 소문자 / 대문자

  • 'abcdefghijklmnopqrstuvwxyz'
  • 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
a = 'hobby'

# 소문자로 바꾸기
s5 = a.lower()
print(s5)
>>> hobby

C = 'a2b3c4'
# 대문자로 바꾸기
C.upper()
>>> 'A2B3C4'

# 주어진 문자열의 맨 첫 글자를 대문자로 바꾸는 함수
C.capitalize()
>>> 'A2b3c4'

# 주어지 문자열에서 알파벳 외의 문자(숫자, 특수문자, 띄어쓰기 등)로 
# 나누어져 있는 첫 글자를 모두 대문자로 바꾸는 함수 : 문자열.title()
C.title()
>>> 'A2B3B4'

# 소문자 확인
a.islower()
>>> True

# 대문자 확인
a.isupper()
>>> False
# 알파벳인지 확인하기
Ex1 = 'ABC'
print(Ex1.isalpha())
>>> True
Ex2 = "100Appia"
print(Ex2.isalpha())
>>> False

# 숫자인지 확인하기
Ex1 = '123456'
print(Ex1.isdigit())
>>> True
Ex2 = "R4R3"
print(Ex2.isdigit())
>>> False
 

# 알파벳 혹은 숫자인지 확인하기
Ex1 = 'Hello3'
print(Ex1.isalnum())
>>> True
Ex2 = "1.Where" 
print(Ex2.isalnum())
>>> False
반응형

+ Recent posts