Sad Puppy 3 '코딩테스트/문제 풀이 - Python' 카테고리의 글 목록 (4 Page) :: 개발자 아지트

https://swexpertacademy.com/main/code/problem/problemDetail.do

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

문제 해결 방법 및 코드 구현

 


t = int(input())

for i in range(t):
    stringg = input()
    stackk = []
    check = 0
    prin = ""
    if len(stringg) % 2 == 0:
        #짝수
        checkN = (len(stringg) // 2) - 1
        for idx, j in enumerate(stringg):
            if idx <= checkN:
                stackk.append(j)
            else:
                if stackk.pop() == j:
                    check = 1
                else:
                    check = 0
    else:
        #홀수
        checkN = (len(stringg) - 1) // 2
        for idx, j in enumerate(stringg):
            if idx < checkN:
                stackk.append(j)
            elif idx == checkN:
                pass
            else:
                if stackk.pop() == j:
                    check = 1
                else:
                    check = 0
    
    
    prin +="#"+str(i+1)+" "+str(check)
    print(prin)

 

 

시간/공간 복잡도

 

최악의 경우 O(N)

 

 

최적화 및 개선

따로 하지않음

 

 

어려웠던 점 / 느낀점

 

D3으로 가야겠다.

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

 

프로그래머스

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

programmers.co.kr

 

 

문제설명

 

가로, 세로 길이가 n인 정사각형으로된 체스판이 있습니다. 체스판 위의 n개의 퀸이 서로를 공격할 수 없도록 배치하고 싶습니다.

 

예를 들어서 n 4인경우 다음과 같이 퀸을 배치하면 n개의 퀸은 서로를 한번에 공격 할 수 없습니다.

 

 

 

체스판의 가로 세로의 세로의 길이 n이 매개변수로 주어질 때, n개의 퀸이 조건에 만족 하도록 배치할 수 있는 방법의 수를 return하는 solution함수를 완성해주세요.

 

문제 해결 방법

 

일단 백트래킹으로 문제를 구현할 생각을 했다. 

그리고 체스판을 1차원으로 생각하려 했다. 

0부터 n까지의 행에 대해서 차례대로 들어가는 값은 하나의 n크기의 리스트에 담을 수 있다. 

 

반복문으로 0부터 n까지의 행을 조회한다. 하나의 행에 대한 열을 모두 조회한다. 

조회를 마치면 다음 행으로 넘어가 그 행에 대한 열을 모두 조회한다. 

.

단, 조회시 조건이 붙는다. 

퀸의 특성은 위 아래 양 옆, 하나의 말에서 나갈 수 있는 대각선 모든 방향 즉, 8개의 방향으로 체스판 끝까지 공격이 가능하다. 

 

하나의 행의 특정 열에 대해서 다음 행은 그 특정 열과 같으면 안된다.  (공격당함)

대각선을 구분하는 방법은 가려는 위치와 기존에 있던 말들의 위치에 대해서 가로 간격과 세로간격이 같으면 대각선이되니 그자리는 못가는 자리다. (공격당함)

 

이렇게 조회하는 과정을 백트래킹을 통해 조회한다면, 불필요한 조회를 줄일 수 있을 것이다. 

 

 

 

코드 구현

 

 

 

def solution(n):
    answer = []
    # 퀸은 위, 아래, 양옆, 대각선으로 공격할 수 있음
    check = []
    
    def backTrack(check, cnt, answer):
        #print(len(answer), check, cnt ,'check, cnt, answer')
        if cnt >= n and len(check) >= n:
            answer.append(check)
            return answer
        
        for row in range(n):
            if row not in check: # 같은 행인지 체크 
                contition = 0
                for idx,i in enumerate(check):
                    if abs(row - i) == abs(cnt - idx):
                        contition = 1
                        break
                    else:
                        contition = 0
                    
                if contition == 0:
                    check.append(row)
                    cnt += 1
                    backTrack(check, cnt, answer)
                    cnt -= 1
                    check.pop()
                    
    cnt = 0
    for col in range(n):
        check.append(col)
        cnt += 1
        backTrack(check, cnt, answer)
        check.pop()
        cnt -= 1
    
    #print('answer', answer)
    
    answer = len(answer)
    
    return answer

 

 

시간/공간 복잡도

 

최악의 경우 O(N!)

 

 

최적화 및 개선

따로 하지않음

 

 

어려웠던 점

 

저번주인가 진짜 백트래킹 너무 어려워서 토나올뻔 했는데, 이제 좀 괜찮다. 신기하다.

N-Queen문제 예전에는 진짜 손도 못댔는데, 이번에는 혼자 잘 풀어서 기분이 아주 최고다 야호~~~~~~~~~~~~~~

(쫌만 더하면 풀릴 것 같고 그래서 3시간 잡고 있었던건 안비밀)

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

 

프로그래머스

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

programmers.co.kr

 

 

문제설명

 

한국중학교에 다니는 학생들은 각자 정수 번호를 갖고 있습니다. 이 학교 학생 3명의 정수 번호를 더했을 때 0이 되면 3명의 학생은 삼총사라고 합니다. 예를 들어, 5명의 학생이 있고, 각각의 정수 번호가 순서대로 -2, 3, 0, 2, -5일 때, 첫 번째, 세 번째, 네 번째 학생의 정수 번호를 더하면 0이므로 세 학생은 삼총사입니다. 또한, 두 번째, 네 번째, 다섯 번째 학생의 정수 번호를 더해도 0이므로 세 학생도 삼총사입니다. 따라서 이 경우 한국중학교에서는 두 가지 방법으로 삼총사를 만들 수 있습니다.

 

한국중학교 학생들의 번호를 나타내는 정수 배열 number가 매개변수로 주어질 때, 학생들 중 삼총사를 만들 수 있는 방법의 수를 return 하도록 solution 함수를 완성하세요.

 

문제 해결 방법

 

파이썬의 조합으로도 풀 수 있었지만, 백트래킹으로 문제를 풀었다. 

 

number리스트의 원소별로 학생의 번호를 달았다. 왜냐하면 문제 제한 사항에 서로 다른 학생의 정수 번호가 같을 수 있다는 문구때문이다. 예를들어 number리스트에 학생 10명이 있다고 가정했을때, 5명의 정수 번호가 0이면 학생 번호로 구분해야한다. 

 

number리스트를 방문 여부를 체크하면서 조건에 맞게 재귀 호출을 한 경우 카운트를 매기며, 총 카운트가 3이되면, 더이상 재귀 호출을 하지 않게끔 했다. 

 

카운트가 3이 됐을때, 문제의 조건(삼총사의 정수 번호 합이 0인 경우)에도 부합하면 totalResult에 삼총사를 추가한다. 

 

최종적으로 totalResult가 만들어졌으면, 중복된 요소들을 삭제하기 위해 요소들을 tuple형태로 바꾸어 주고, 리스트를 최종적으로 set() 으로 변경하기 좋은 상태를 만든다. 

 

준비가 되었으면 set()으로 변경해주면 중복 요소 처리를 할 수 있다. 

 

정리된 집합의 원소 수를 세면 그것이 정답이다. 

 

 

코드 구현

 

 

dfs를 통해 구현한 코드 

 

# 3명의 정수 번호를 더했을 때 0이 되면 3명의 학생은 삼총사
def solution(number):
    answer = 0
    
    newL = []
    for idx, i in enumerate(number):
        newL.append([idx, i])
        
    totalResult = []
    
    def dfs(cnt, visited, summ, result, totalResult):
        for idx, i in enumerate(newL):
            if visited[idx] == False:
                cnt += 1
                summ += i[1]
                visited[idx] = True
                result.append(i)
                
                if cnt == 3 and summ == 0:
                    totalResult.append(result[:])
                
                if cnt < 3:
                    dfs(cnt, visited, summ, result, totalResult)
                    
                visited[idx] = False
                cnt -= 1
                summ -= i[1]
                result.pop()
                
    for idx, i in enumerate(newL):
        summ, cnt = 0, 0
        result = []
        visited = [False] * len(newL)
        visited[idx] = True
        cnt+=1
        summ+=i[1]
        result.append(i)
        dfs(cnt, visited, summ, result, totalResult)
        
    
    newS = set()
    tmpL = []
    for i in totalResult:
        tmpL = sorted(i, key = lambda x:x[0])
        tuple_arr = [tuple(i) for i in tmpL]
        newS.add(tuple(tuple_arr))
        

    answer = len(newS)
    
    return answer

 

 

시간/공간 복잡도

 

최악의 경우 O(N!)

 

 

최적화 및 개선

 

재귀 함수 호출시 불필요한 매개변수를 삭제함

 

 

어려웠던 점

 

이번 문제는 진짜 어려웠다. 

특히 백트래킹을 구현할 때 계속 시간초과가 났다. 분명히 코드는 제대로 작성한것 같다고 생각했다. 

코드를 분석해보니, 문제 조건과 카운트 수가 맞아서 totalResult에 삼총사를 추가하고나서 다음 절차를 진행할 때, totalResult내부의 값이 자꾸 바뀌는 문제가 발생했다. 알아보니 리스트를 새로 만들어주지 않고 계속 똑같은 리스트가 뒤에 절차를 진행할 때도 재활용된다는 문제였다. 이를 위해서 리스트 슬라이싱을 통해 새로운 리스트를 만드는 식으로 코드를 변경했더니 문제가 해결됐다. 

 

이 이후에는 자꾸 대부분의 테스트케이스에서 시간 초과가 났다. 

진짜 분명 코드는 제대로 작성한 것 같다고 생각했다. 

 

그런데 아뿔싸 설마,,?

 

재귀 호출을 할때, 카운트 제한(3)을 조건문으로 걸어주지 않아서 시간 초과가 나는건가?

맞았다. 이때문에 불필요한 재귀 호출을 마구마구마구 하기 때문에 시간 초과가 났었다. 

해당 조건을 추가해주고 나니 더이상 시간 초과가 나지 않았다. 

 

그리고 리스트 원소를 중복제거 하기 위해서 집합자료형으로 바꾸는 과정에서 애를 먹었다. 

그냥 일반 리스트면 몰라도 이중 리스트는 쉽지 않았다!!! 내부의 내부의 리스트를 튜플로 변경시켜주고, 그것들을 감싸고있는 껍데기도 튜플로 변경시켜줘야 한다. 그러면 Hashable 자료형인 튜플로 변경할 수 있게된다..!!!!!!

 

lv1짜리 문제지만, 내가 알고있는 파이썬 문법에 구멍이 있다는 것을 크게 깨달았다. 이대로 정진!!!!!!!

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

 

 

프로그래머스

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

programmers.co.kr

 

 

문제설명

 

XX게임에는 피로도 시스템(0 이상의 정수로 표현합니다)이 있으며, 일정 피로도를 사용해서 던전을 탐험할 수 있습니다. 이때, 각 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"와 던전 탐험을 마쳤을 때 소모되는 "소모 피로도"가 있습니다. "최소 필요 피로도"는 해당 던전을 탐험하기 위해 가지고 있어야 하는 최소한의 피로도를 나타내며, "소모 피로도"는 던전을 탐험한 후 소모되는 피로도를 나타냅니다. 예를 들어 "최소 필요 피로도" 80, "소모 피로도" 20인 던전을 탐험하기 위해서는 유저의 현재 남은 피로도는 80 이상 이어야 하며, 던전을 탐험한 후에는 피로도 20이 소모됩니다.

 

이 게임에는 하루에 한 번씩 탐험할 수 있는 던전이 여러개 있는데, 한 유저가 오늘 이 던전들을 최대한 많이 탐험하려 합니다. 유저의 현재 피로도 k와 각 던전별 "최소 필요 피로도", "소모 피로도"가 담긴 2차원 배열 dungeons 가 매개변수로 주어질 때, 유저가 탐험할수 있는 최대 던전 수를 return 하도록 solution 함수를 완성해주세요.

 

 

제한사항

 

k 1 이상 5,000 이하인 자연수입니다.

dungeons의 세로() 길이(, 던전의 개수) 1 이상 8 이하입니다.

dungeons의 가로() 길이는 2 입니다.

dungeons의 각 행은 각 던전의 ["최소 필요 피로도", "소모 피로도"] 입니다.

"최소 필요 피로도"는 항상 "소모 피로도"보다 크거나 같습니다.

"최소 필요 피로도" "소모 피로도" 1 이상 1,000 이하인 자연수입니다.

서로 다른 던전의 ["최소 필요 피로도", "소모 피로도"]가 서로 같을 수 있습니다.

 

입출력 예

 

k         dungeons         result

80        [[80,20],[50,40],[30,10]]      3

 

입출력 예 설명

 

현재 피로도는 80입니다.

 

만약, 첫 번째  두 번째  세 번째 던전 순서로 탐험한다면

 

현재 피로도는 80이며, 첫 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 또한 80이므로, 첫 번째 던전을 탐험할 수 있습니다. 첫 번째 던전의 "소모 피로도" 20이므로, 던전을 탐험한 후 남은 피로도는 60입니다.

남은 피로도는 60이며, 두 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 50이므로, 두 번째 던전을 탐험할 수 있습니다. 두 번째 던전의 "소모 피로도" 40이므로, 던전을 탐험한 후 남은 피로도는 20입니다.

남은 피로도는 20이며, 세 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 30입니다. 따라서 세 번째 던전은 탐험할 수 없습니다.

 

만약, 첫 번째  세 번째  두 번째 던전 순서로 탐험한다면

 

현재 피로도는 80이며, 첫 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 또한 80이므로, 첫 번째 던전을 탐험할 수 있습니다. 첫 번째 던전의 "소모 피로도" 20이므로, 던전을 탐험한 후 남은 피로도는 60입니다.

남은 피로도는 60이며, 세 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 30이므로, 세 번째 던전을 탐험할 수 있습니다. 세 번째 던전의 "소모 피로도" 10이므로, 던전을 탐험한 후 남은 피로도는 50입니다.

남은 피로도는 50이며, 두 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 50이므로, 두 번째 던전을 탐험할 수 있습니다. 두 번째 던전의 "소모 피로도" 40이므로, 던전을 탐험한 후 남은 피로도는 10입니다.

따라서 이 경우 세 던전을 모두 탐험할 수 있으며, 유저가 탐험할 수 있는 최대 던전 수는 3입니다.

 

문제 해결 방법

 

1. dungeons에서 모두 나올 수 있는 순서에 대해 경우의 수를 순열로 뽑는다.

2. 리스트를 하나 만들고, 순열로 뽑은 모든 경우의 수에 대해서 조건을 따져가면서 던전에 방문한 횟수를 카운트 하여 최종적으로 카운트 한 수를 해당 리스트에 추가한다. 

2-1. 위에서 말한 조건으로 각 던전의 최소 필요 피로도가  k와 같거나 커야지 던전에 방문할 수 있으니 해당하는 조건을 체크한다. 

2-2. 만약 k가 특정 던전에 방문할 수 있다면 k에서 소모 피로도를 빼준다. 

3. 2번에서 만든 리스트에서 max값을 구하여 출력한다. 

 

코드 구현

 

조합으로 구현한 과거의 코드 

 

더보기

 

from itertools import permutations

def solution(k, dungeons):
    answer = -1
    
    cpk=k
    cases = list(permutations(dungeons, len(dungeons)))
    checkList=[]
    
    for i in range(len(cases)):
        cpK=k
        checkcheck = 0
        for j in range(len(cases[i])):
            if cpK >= cases[i][j][0]:
                cpK = cpK - cases[i][j][1]
                checkcheck += 1
            else:
                pass
            
            if j == len(cases[i])-1:
                checkList.append(checkcheck)

    answer = max(checkList)
    
    return answer

 

 

 

주석 포함 코드

 

 

from itertools import permutations

def solution(k, dungeons):
    answer = -1
    
    #print('k', k, 'dungeons', dungeons)
    # 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"
    # 던전 탐험을 마쳤을 때 소모되는 "소모 피로도"
    
    #최소 필요 피로도"가 80, "소모 피로도"가 20인 던전을 탐험하기 위해서는 유저의 현재 남은 피로도는 80 이상 이어야 하며, 던전을 탐험한 후에는 피로도 20이 소모됨
    
    #하루에 한 번씩 탐험할 수 있는 던전이 여러개
    
    # 1. dungeons는 [0]기준 MAX를 뽑는다. 
    # 2. dungeons의 순열을 뽑는다. 
    
    
    cpk=k
    
    
    cases = list(permutations(dungeons, len(dungeons)))
    #print(cases)
    
    checkList=[]
    #print("")
    
    for i in range(len(cases)):
        #maxx = cases[i][0][0]
        cpK=k
        #print("1 cpK", cpK)
        checkcheck = 0
        #print('i', i, cases[i])
        for j in range(len(cases[i])):
            #print('j', j, cases[i][j])

            if cpK >= cases[i][j][0]:
                cpK = cpK - cases[i][j][1]
                #print('cpK', cpK)
                checkcheck += 1
            else:
                pass
            
            if j == len(cases[i])-1:
                checkList.append(checkcheck)
            
        #print("")
        #print("")


    #print(checkList)
            
    answer= max(checkList)
    
    return answer

 

 

 

 

 

dfs를 통해 구현한 현재 코드 

 

 

def solution(k, dungeons):
    answer = []
    # k - 현재 피로도, 하루 한번 탐험가능한 던전 dungeons
    # 유저가 탐험할 수 있는 최대 던전 수 
    
    cnt = len(dungeons)
    visited = [False] * cnt
    
    def check2(k, iz, io):
        if k >= iz:
            return k - io
        else:
            return None
    
    def check(k, cnt, visited):
        answer.append(cnt)
        
        for idx, i in enumerate(dungeons):
            cs, sm = i
            if check2(k, cs, sm) and visited[idx] == False:
                kk = check2(k, cs, sm)
                visited[idx] = True
                check(kk, cnt + 1, visited)
                visited[idx] = False
                # 예를들어서 1, 2, 3, 4, 5 가 있는데 조건 때문에 1, 2, 3까지 방문을 마치고 기록을 했다. 근데 이제 1, 2까지 온 상태에서 3을 빼고 나머지 4, 5와도 조합을 했을때 조건이 맞을 수 있기 때문에 3에 대한 방문을 false처리하고 나머지를 탐색해봐야해서 
                # visited[idx] = False 코드가 필요한 것임. 

    for idx, i in enumerate(dungeons):
        visited = [False] * len(dungeons)
        
        cs, sm = i
        if check2(k, cs, sm):
            valueK = check2(k, cs, sm)
            visited[idx] = True
            check(valueK, 1, visited)
    
    print(answer)
    answer = max(answer)
    
    return answer

 

 

 

시간/공간 복잡도

 

최악의 경우 O(N!)

 

 

최적화 및 개선

 

dfs로 구현함

 

어려웠던 점

 

 

과거

 

더보기

안풀어본 문제유형(완전탐색)이라 완전 쫄았다. 완전탐색 문제를 풀기위해서 대략 어떤 알고리즘이 필요한지 찾아보고 일단은 대충이라도 공부했다. (요즘 좀 바쁨) 암튼 대충 이런저런 방법으로 생각해보다가 문제를 풀었다 .


진짜 내가 이 문제를 푼거에 대해서 아주 놀랍다 하하 박수 ~~~ 짝짝~~

생각보다 진짜 별거아니네 !!! 쫄지마 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

 

현재

 

완전탐색으로 풀기 어렵다. 재귀가 진짜 어렵다. 

하.. 산넘어 산이야~ 

진짜 어렵다. 특히 탐색 후에 방문 처리했던것을 방문 안한것으로 후처리 해주는 이유가 와닿지 않아서 엄청 시간 보냈다. 

 

 

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

 

프로그래머스

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

programmers.co.kr

 

문제설명

 

 

 

위와 같은 삼각형의 꼭대기에서 바닥까지 이어지는 경로 중, 거쳐간 숫자의 합이 가장 큰 경우를 찾아보려고 합니다. 아래 칸으로 이동할 때는 대각선 방향으로 한 칸 오른쪽 또는 왼쪽으로만 이동 가능합니다. 예를 들어 3에서는 그 아래칸의 8 또는 1로만 이동이 가능합니다.

 

삼각형의 정보가 담긴 배열 triangle이 매개변수로 주어질 때, 거쳐간 숫자의 최댓값을 return 하도록 solution 함수를 완성하세요.

 

문제 해결 방법

 

triangle을 순회할때, n번째 리스트의 각 원소를 기준으로 n-1번째 리스트에서 자신이 거쳐올 수 있었던 원소 후보 중에서 큰 값을 자신과 더해나가면 된다. 

 

 

코드 구현

 

def solution(triangle):
    answer = 0
    
    for idx, i in enumerate(triangle):
        if idx == 0:
            continue
            
        for cnt, j in enumerate(i):
            if cnt == 0:
                i[cnt] = triangle[idx-1][cnt] + i[cnt]
            elif cnt == len(i)-1:
                i[cnt] = triangle[idx-1][cnt-1] + i[cnt]
            else:
                if triangle[idx-1][cnt-1] > triangle[idx-1][cnt]:
                    i[cnt] = triangle[idx-1][cnt-1] + i[cnt]
                else:
                    i[cnt] = triangle[idx-1][cnt] + i[cnt]
        if len(triangle)-1 == idx:
            answer = max(triangle[idx])
    
    
    return answer

 

시간/공간 복잡도

 

O(n^2)

 

최적화 및 개선

 

따로 하지 않음

 

어려웠던 점

 

재귀함수로 구현해야하나 스택으로 구현해야하나 고민했지만 굳이 그렇게 구현할 필요 없었다. 

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

 

프로그래머스

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

programmers.co.kr

 

 

문제설명

 

다음 그림과 같이 지뢰가 있는 지역과 지뢰에 인접한 위, 아래, , 우 대각선 칸을 모두 위험지역으로 분류합니다.

 

 

지뢰는 2차원 배열 board 1로 표시되어 있고 board에는 지뢰가 매설 된 지역 1, 지뢰가 없는 지역 0만 존재합니다.

지뢰가 매설된 지역의 지도 board가 매개변수로 주어질 때, 안전한 지역의 칸 수를 return하도록 solution 함수를 완성해주세요.

 

 

 

문제 해결 방법

 

폭탄 주변에 지뢰와 인접한 지역을 판단할 좌표를 미리 만들어두고, 지도를 탐색할 때, 폭탄이 발견되는 경우, 주변을 지뢰 인접 지역으로 표시하면된다. 

 

 

 

코드 구현

 

def solution(board):
    answer = 0
    
    dx = [0, 0, -1, 1, -1, 1, -1, 1]
    dy = [1, -1, 0, 0, 1, 1, -1, -1]
    
    m = len(board) 
    
    for idx, i in enumerate(board):
        for idx2, j in enumerate(i):
            if j == 1:
                # 상, 하, 좌, 우, 대각선 4개 다 -1칠하기 
                for k in range(8):
                    
                    nx = idx+dx[k]
                    ny = idx2+dy[k]
                    
                    if nx<0 or ny<0 or nx>=m or ny>=m:
                        continue
                    
                    
                    if board[nx][ny]==1:
                        continue
                        
                    elif board[nx][ny]==-1:
                        continue
                        
                    elif board[nx][ny]==0:
                        board[nx][ny]=-1

    
    for i in board:
        for j in i:
            if j == 0:
                answer+=1

    return answer

 

시간/공간 복잡도

 

O(n^2)

 

최적화 및 개선

 

따로 하지 않음

 

어려웠던 점

 

없음.

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

 

프로그래머스

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

programmers.co.kr

 

 

 

문제설명

 

하노이 탑(Tower of Hanoi)은 퍼즐의 일종입니다. 세 개의 기둥과 이 기동에 꽂을 수 있는 크기가 다양한 원판들이 있고, 퍼즐을 시작하기 전에는 한 기둥에 원판들이 작은 것이 위에 있도록 순서대로 쌓여 있습니다. 게임의 목적은 다음 두 가지 조건을 만족시키면서, 한 기둥에 꽂힌 원판들을 그 순서 그대로 다른 기둥으로 옮겨서 다시 쌓는 것입니다.

 

한 번에 하나의 원판만 옮길 수 있습니다.

큰 원판이 작은 원판 위에 있어서는 안됩니다.

하노이 탑의 세 개의 기둥을 왼쪽 부터 1, 2, 3번이라고 하겠습니다. 1번에는 n개의 원판이 있고 이 n개의 원판을 3번 원판으로 최소 횟수로 옮기려고 합니다.

 

1번 기둥에 있는 원판의 개수 n이 매개변수로 주어질 때, n개의 원판을 3번 원판으로 최소로 옮기는 방법을 return하는 solution를 완성해주세요.

 

 

문제 해결 방법

 

재귀 함수를 이용하여 문제를 해결하면 된다.

 

n개의 원판을 x에서 y로 움직여야 하는 경우, 로직은 다음과 같다. 

1. n-1개의 원판을 x번 기둥에서 6-x-y번 기둥으로 옮긴다.
       (n이 1이 될 때까지, n이 1이 되는 경우 x번기둥에서 y번 기둥으로 바로 옮겨준다. )

2. n번째 원판을 x번 기둥에서 y번 기둥으로 옮긴다.

3. n-1개의 원판을 6-x-y번 기둥에서 3번 기둥으로 옮긴다. (n이 1이 될 때까지)

       (n이 1이 될 때까지, n이 1이 되는 경우 x번기둥에서 y번 기둥으로 바로 옮겨준다. )

 

 

 

코드 구현

 

def hanoi(n, answer, x, y):
    if n == 1:
        answer.append([x, y])
        return
    hanoi(n-1, answer, x, 6-x-y)
    answer.append([x, y])
    hanoi(n-1, answer, 6-x-y, y)

def solution(n):
    answer = []
    hanoi(n, answer, 1, 3)
    return answer

 

 

코드 구현시 재귀 함수의 원리

 

시간/공간 복잡도

 

O(2^n)

 

최적화 및 개선

 

따로 하지 않음

 

어려웠던 점

 

해당 문제의 코드는 직접 원판을 옮기면서 검증해봐야  재귀함수가 이해될 수 있다.  

아직까지 한번도 접해보지 않은 유형에 대해 재귀함수로 문제를 풀어보라하면 어려움을 겪는다. 

너무 어렵다 ㅠㅠ..

코드는 간단한데 원리에 대한 생각과 구현이 너무 어렵다.

 

https://vidkidz.tistory.com/649

 

하노이의 탑 (Tower of Hanoi)

하노이탑 (Tower of Hanoi) 플래시게임입니다 다음 두가지 조건을 만족시키면서 첫번째 기둥에 있는 원판들을 세번째 기등으로 그대로 옮기는 퍼즐 게임입니다 1. 한번에 하나의 원판만 옮길 수 있

vidkidz.tistory.com

 

해당 사이트에서 직접 하노이의 탑의 원판을 옮겨가면서 검증했다. 

 

 

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

 

프로그래머스

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

programmers.co.kr

 

 

 

문제설명

n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.

 

송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값) return 하도록 solution 함수를 완성해주세요.

 

문제 해결 방법

 

그래프로 구현하고 dfs로 송전탑의 개수를 세아렸다. 

 

코드 구현

 

def dfs(newGraph, visited, node):
    visited[node] = True
    cnt=1
    for injeop in newGraph[node]:
        if visited[injeop] == False:
            cnt += dfs(newGraph, visited, injeop)
    return cnt


def solution(n, wires):
    answer = -1
    
    # 그래프 생성
    graph = [[] for _ in range(n+1)]
    for v1, v2 in wires:
        graph[v1].append(v2)
        graph[v2].append(v1)
    
    
    Totalcntlist = []
    for i in range(1, n+1):
        for value in graph[i]:
            # print('어디보자---^^^')
            # print('graph[', i, ']: ', graph[i], 'value: ',value)
            idxOne = graph[value].index(i)
            graph[value].remove(i) 
            idxTwo = graph[i].index(value)
            graph[i].remove(value)
            
            cntlist=[]
            visited = [False] * (n+1)
            for j in range(1, n+1):
                if visited[j] == False:
                    cnt = dfs(graph, visited, j)
                    cntlist.append(cnt)     
            # print(cntlist)
            sum = abs(cntlist[0]-cntlist[1])
            Totalcntlist.append(sum)
            
            # graph[value].append(i) # 문제의 코드 
            # graph[i].append(value)  
            # print('graph[', i, ']: ', graph[i])
            # print('결과보자 ---vvv')
            graph[value].insert(idxOne, i)
            graph[i].insert(idxTwo, value)
            
    answer = min(Totalcntlist)
    return answer

 

 

 

문제의 코드 

 

더보기

 

문제의 코드 1. 

 

import copy
def dfs(newGraph, visited, node):
    visited[node] = True
    cnt=1
    for injeop in newGraph[node]:
        if visited[injeop] == False:
            cnt += dfs(newGraph, visited, injeop)
    return cnt

def solution(n, wires):
    answer = -1
    graph = [[] for _ in range(n+1)]
    for v1, v2 in wires:
        graph[v1].append((v2))
        graph[v2].append((v1))
    originGraph = copy.deepcopy(graph)
    # 설마 일일이 다 끊어서 dfs구하라 그건가? ;; 방문은 visited로 한다. 
    
    newgraph = copy.deepcopy(originGraph)
    #print(newgraph)
    Totalcntlist = []
    for i in range(1, n+1):
        # 끊는 대상 = i
        # index가 i 인곳에서 연결된거 다 빼야함
        for value in newgraph[i]:
            newgraph[value].remove(i)
            newgraph[i].remove(value)
    
            #print('i:', i,'value', value,': ',newgraph)
            # 이때 나온 그래프로 dfs를 하면됨 
            
            cntlist=[]
            visited = [False] * (n+1)
            for j in range(1, n+1):
                if visited[j] == False:
                    cnt = dfs(newgraph, visited, j)
                    cntlist.append(cnt)
            #print('cntlist', cntlist)
            sum = abs(cntlist[0]-cntlist[1])
            Totalcntlist.append(sum)
            newgraph[value].append(i)
            newgraph[i].append(value)
            #newgraph = copy.deepcopy(originGraph) # deppcopy때문
    #print('Totalcntlist', min(Totalcntlist))    
    answer = min(Totalcntlist)
    return answer

 

 

 

문제의 코드 2.

 

import copy
def dfs(newGraph, visited, node):
    visited[node] = True
    cnt=1
    for injeop in newGraph[node]:
        if visited[injeop] == False:
            cnt += dfs(newGraph, visited, injeop)
    return cnt

def solution(n, wires):
    answer = -1
    graph = [[] for _ in range(n+1)]
    for v1, v2 in wires:
        graph[v1].append(v2)
        graph[v2].append(v1)
    # 설마 일일이 다 끊어서 dfs구하라 그건가? ;; ㅅㅂ ㅠㅠ 방문은 visited로 한다. 
    
    #print(newgraph)
    Totalcntlist = []
    for i in range(1, n+1):
        # 끊는 대상 = i
        # index가 i 인곳에서 연결된거 다 빼야함
        for value in graph[i]:
            graph[value].remove(i)
            graph[i].remove(value)
    
            
            cntlist=[]
            visited = [False] * (n+1)
            for j in range(1, n+1):
                if visited[j] == False:
                    cnt = dfs(graph, visited, j)
                    cntlist.append(cnt)
            #print(cntlist)
            sum = abs(cntlist[0]-cntlist[1])
            Totalcntlist.append(sum)
            
            graph[value].append(i)
            graph[i].append(value)  
            
    answer = min(Totalcntlist)
    return answer

 

 

 

시간/공간 복잡도

 

O(N^2)

 

최적화 및 개선

 

따로 하지않음

 

어려웠던 점

진짜 로직 구현은 어찌저찌 잘 해결했어도, graph 간선끊었다가 원상복구 하는 부분에서 애를 많이 먹었다. 

처음에 간선 끊고 원상복구를 하려고 일반 리스트에 그냥 대입연산자로 대입을 했었는데, 웬걸 먹히지 않았다. 

 

파이썬에서 immutable한 특징을 가진 자료형(예를들면, int)의 경우, 객체 생성이 된 후 값 수정이 불가하다. 

따라서 처음에 값을 선언한 후 다른 변수에 값을 대입하고 그 변수의 값을 변경해도, 처음 선언한 변수의 값은 변하지 않는다. 

 

반대로, muteable한 객체는 다르다. (예를들면, list)

처음에 리스트를 선언한 후 다른 변수에 리스트를 대입하고 그 변수의 값 일부를 변경하면, 처음 선언한 리스트의 값 일부까지 변한다.  

 

처음 선언한 리스트는 a리스트이고, 다른 변수 리스트는 b라고 가정한다. 

이 경우에서는 리스트 a와 리스트 b는 같은 주소를 참조한다. 따라서 b 리스트의 요소가 변경되면, a 리스트도 똑같이 변경된다. 

 

그래서 찾아보니 deepcopy를 해야한다고 했다.

 

deepcopy로 문제를 풀어보니 전보단 확실히 정답률이 높아졌는데 몇몇 테스트 케이스가 틀렸다. 확인해보니 deepcopy를 제대로 못쓰고 있는것 같이 계속 특정 부분에서 구멍이 났다. 그래서 일일이 끊은 간선을 다시 붙여주는 작업을 했다. 

 

그 작업에서 append를 사용했더니 원래 있던 자리에서 원소가 맨 뒤에 붙었다. 이게 이제 그래프 순환할때 문제가 됐다. 

특정 테스트 케이스의 경우 자꾸 어떤 경우만 빼고 dfs를 진행해서 틀렸다. 

 

이 문제를 해결하고 나니 deepcopy 가 왜 안됐었는지 알 것같았다. 

 

경로를 아무리 끊는다고 해도 순환할 때의 기준이 되는 기준점은 변경되면 안된다. 

 

코드로 설명하면 다음과 같다. 

 

import copy
def dfs(newGraph, visited, node):
    visited[node] = True
    cnt=1
    for injeop in newGraph[node]:
        if visited[injeop] == False:
            cnt += dfs(newGraph, visited, injeop)
    return cnt


def solution(n, wires):
    answer = -1
    
    # 그래프 생성
    graph = [[] for _ in range(n+1)]
    for v1, v2 in wires:
        graph[v1].append(v2)
        graph[v2].append(v1)
    
    newGraph = copy.deepcopy(graph)
    
    Totalcntlist = []
    for i in range(1, n+1):
        for value in graph[i]: # 기준점 graph는 변경되면 안된다. 
            idxOne = newGraph[value].index(i)
            newGraph[value].remove(i) 
            idxTwo = newGraph[i].index(value)
            newGraph[i].remove(value)
            
            cntlist=[]
            visited = [False] * (n+1)
            for j in range(1, n+1):
                if visited[j] == False:
                    cnt = dfs(newGraph, visited, j)
                    cntlist.append(cnt)     
            sum = abs(cntlist[0]-cntlist[1])
            Totalcntlist.append(sum)      
            
            newGraph = copy.deepcopy(graph)
            
    answer = min(Totalcntlist)
    return answer

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

 

프로그래머스

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

programmers.co.kr

 

문제설명

 

링크 참고

 

 

문제 해결 방법

 

다익스트라알고리즘을 적용해 문제를 해결하였음

 

 

 

코드 구현

 

def solution(N, road, K):
    answer = 0
    
    distances = [float("inf")] * (N+1) 
    distances[0] = 0 # 0과 1은 사용하지 않음
    distances[1] = 0
    
    
    for i in range(N-1):
        for i in range(1, N+1):
            for nodeSet in road:
                fromm, to, weight = nodeSet
                if fromm == i:
                    distance = distances[i] + weight
                    if distance < distances[to]:
                        distances[to] = distance

                to, fromm, weight = nodeSet
                if fromm == i:
                    distance = distances[i] + weight
                    if distance < distances[to]:
                        distances[to] = distance
                    

    # N개의 마을 중에서 K시간 이하로 배달이 가능한 마을에서만 주문을 받으려고함
    # 1번 마을에 있는 음식점이 음식 주문을 받을 수 있는 마을의 개수를 return 
    
    # a, b = 마을의 번호 c = 도로를 지나는데 걸리는 시간
    
    # 그래프 만들기 
    answer +=1
    for i in distances:
        if i <= K and i>0:
            answer+=1
    
    return answer

 

 

 

시간/공간 복잡도

O((N+E)N)

 

최적화 및 개선

하지않음... 

 

 

어려웠던 점

 

양방향 이동이라는 점을 잘 새겨봤어야 했다. 코드를 짜다보니 나도 모르게 단방향으로 코드를 작성했다. 

다익스트라 알고리즘은 n-1번 반복해야 하는 것을 잘 기억해야겠다. 

처음에 코드 작성후, 채점하니 40점이 나왔는데 혹시나 해서 최단거리 구하는 코드를 한번더 복사 붙여넣기 한 후 채점하니 50점이 나왔다. 그 후 힌트를 얻기위해 책을 한번더 보고, 그 후 한번 더 복사 붙여넣기 하니 80점이 나왔는데 그때 깨달았다.. 

 

 

 

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

 

프로그래머스

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

programmers.co.kr

 

 

문제설명

네트워크란 컴퓨터 상호 간에 정보를 교환할 있도록 연결된 형태를 의미합니다. 예를 들어, 컴퓨터 A 컴퓨터 B 직접적으로 연결되어있고, 컴퓨터 B 컴퓨터 C 직접적으로 연결되어 있을 컴퓨터 A 컴퓨터 C 간접적으로 연결되어 정보를 교환할 있습니다. 따라서 컴퓨터 A, B, C 모두 같은 네트워크 상에 있다고 있습니다.

 

컴퓨터의 개수 n, 연결에 대한 정보가 담긴 2차원 배열 computers 매개변수로 주어질 , 네트워크의 개수를 return 하도록 solution 함수를 작성하시오.

 

문제 해결 방법

 

 

이런 문제는 최적의 해 보다는 모든 요소를 탐색하는 것이 목적이다.

모든 요소를 탐색하기 위해 DFS가 좋다. 

 

computers를 그래프로 표현한 후, 방문 테이블을 만들고, 방문 테이블을 통해 그래프를 DFS로 몇번 탐색 했는지를 출력하면 된다. 

 

 

 

이 문제를 bfs로 풀려고 했던 과거의 내자신 ㅠㅠ 

 

 

 

코드 구현

 

주석 없는 버전

더보기

 

def dfs(computers, visited, node):
        visited[node] = True
        for idx, connected in enumerate(computers[node]):
            if connected and not visited[idx]:
                dfs(computers, visited, idx)

def solution(n, computers):
    answer = 0
    visited = [False] * n
    
    for i in range(n):
        if not visited[i]:
            dfs(computers, visited, i)
            answer += 1
    
    
    return answer

 

 

 

 

 

 

def dfs(computers, visited, node):
    # 조회를 하면 해당 노드에 대해 방문처리를 해준다. 
    # 해당 노드를 통해 computers에 딸린 다른 노드들을 반복문을 통해 조회하고,
        # 연결 여부와 방문 여부를 확인한다. 
    # 연결된 것을 통해 깊이 우선 탐색을 계속 해나간다. 
    visited[node] = True
    for index, connected in enumerate(computers[node]):
        if connected and visited[index] == False:
            dfs(computers, visited, index)
    
def solution(n, computers):
    answer = 0
    # 방문여부를 담는 크기 n만큼의 배열 
    
    visited = [False] * n
    
    for i in range(n):
        if visited[i] == False:
            dfs(computers, visited, i)
            answer+=1
    # 반복문을 통해 노드를 0~n까지 순회하며 깊이 우선 탐색을 한다. 
        # 깊이 우선 탐색 dfs에는 computers라는 그래프와, visited, 그리고 노드를 보내준다. 
    # 깊이 우선 탐색이 끝나면 answer +1 을 해준다. 
    return answer

 

 

시간/공간 복잡도

 

O(N^2)

 

 

최적화 및 개선

 

따로 하지 않음.


어려웠던 점

 

아직 DFS, BFS사용에 서툰것 같다. 

+ Recent posts