루나의 TIL 기술 블로그

백준 2869 달팽이는 올라가고 싶다

|

문제 설명

땅 위에 달팽이가 있다. 이 달팽이는 높이가 V미터인 나무 막대를 올라갈 것이다.

달팽이는 낮에 A미터 올라갈 수 있다. 하지만, 밤에 잠을 자는 동안 B미터 미끄러진다. 또, 정상에 올라간 후에는 미끄러지지 않는다.

달팽이가 나무 막대를 모두 올라가려면, 며칠이 걸리는지 구하는 프로그램을 작성하시오.

사고 과정

v = (a * d) + (-b * (d-1)) 높이 = (올라감 * 걸리는 날짜) + (미끄러짐 * 걸리는 날짜-1)

제출 답안

import math
a, b, v = map(int,input().split()) 
print(math.ceil((v-b)/(a-b)))

주요 포인트 및 생각해볼 점

math.ceil 올림 함수를 사용했다.

백준 10250 ACM호텔

|

백준 - ACM호텔

문제 설명

호텔에서 엘리베이터에 가까운 방 순으로 방을 배정한다.
102호보다 2101호가 엘리베이터에 더 가깝다. 호텔

프로그램은 표준 입력에서 입력 데이터를 받는다. 프로그램의 입력은 T 개의 테스트 데이터로 이루어져 있는데 T 는 입력의 맨 첫 줄에 주어진다. 각 테스트 데이터는 한 행으로서 H, W, N, 세 정수를 포함하고 있으며 각각 호텔의 층 수, 각 층의 방 수, 몇 번째 손님인지를 나타낸다(1 ≤ H, W ≤ 99, 1 ≤ N ≤ H × W).

테스트 데이터마다 정확히 한 행을 출력하는데, N 번째 손님에게 배정되어야 하는 방 번호를 출력한다.

사고 과정

층수(H)만큼 배정하면 방수(W)를 하나씩 올린다. 예를 들어
6층 층별 12방 10번째 손님이면 6x1 +4 니까 402호
30층 층별 50방 72번째 손님이면 30x2 +12 니까 1203호
그래서 계산하면 guest_num % h층 guest_num//h+1호에 배정한다.

n = int(input())
for _ in range(n):
  h, w, guest_num = map(int,input().split()) 
  print(((guest_num%h)*100) + (guest_num//h)+1)

101,201,301..호 일때를 빼먹었다.

제출답안

n = int(input())
for _ in range(n):
  h, w, guest_num = map(int,input().split())
  floor = guest_num%h
  num = guest_num//h+ 1
  if floor == 0:
    print(h*100 + num-1)  
  else:
    print(floor*100 + num)

백준 2839 설탕배달

|

문제 설명

상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.

상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.

상근이가 설탕을 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 구하는 프로그램을 작성하시오. 상근이가 배달하는 봉지의 최소 개수를 출력한다. 정확하게 N킬로그램을 만들 수 없다면 -1을 출력한다.

사고 과정

5로 나눈 몫 + 5로 나눈 나머지를 3으로 나눈 몫이 봉지수일 것이다. 5로 나눈 나머지를 3으로 나눈 나머지가 있는 경우 -1을 출력한다. (무조건 5kg봉지에 먼저 넣을거라고 잘못 생각했다)

n = int(input())
count = 0
if int(n%5%3 != 0):
    print(-1)
else: 
    print(n//5+ n%5//3)    

11에서 틀렸다. 11을 5x2봉지 +1이 아닌 5x1봉지 3x2봉지로 완벽하게 담을 수 있기 때문이다.

그렇다면 완벽하게 담을 수 있는 수를 모두 구하기 위해서
3의 배수와 5의 배수 집합의 원소끼리 더해서 나올 수 있는 모든 값을 출력해볼까?

from itertools import combinations
numbers = set()
answer = set()

for i in range(1,10):
  numbers.add(3*i)
  numbers.add(5*i)
print(sorted(numbers)) #3의 배수와 5의 배수들

for i in list(combinations(numbers,2)):
  answer.add(sum(i))
print (sorted(answer))

설탕 배달

이 집합이 5000까지 나오도록 만든다음 이 리스트에 없으면 -1을 출력하는 코드를 만들어보자.

from itertools import combinations
numbers = set()
answer = set()

for i in range(0,510):
  numbers.add(3*i)
  numbers.add(5*i)
print(sorted(numbers)) #3의 배수와 5의 배수들

for i in list(combinations(numbers,2)):
  answer.add(sum(i))
print (sorted(answer))

n = int(input())
count = 0

if n in answer:
    count = n//5+ n%5//3
    if int(n%5%3 != 0):
        count += 1
    print(count)

if n not in answer:
    print(-1)

길긴 하지만 11을 입력했을 때 3이 잘 나온다. 제출하니 출력 초과가 뜬다.
예전에 제출한 자바코드를 한 번 살펴보자.

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.close(); //이러쿵저러쿵
        // 5로 나눈 몫을 카운트에 저장한다
        int count = n/5;
        // 5로 나눈 나머지가 
        switch (n % 5) {
            //0이라면 카운트를 출력하고
            case 0 :
                System.out.println(count);
                break;
            // 1이나 3이라면 카운트에 1을 더한다
            // 1이면 5대신 3사용, 3이면 3하나 추가
            case 1 :
            case 3 :
                System.out.println(count+1);
                break;
            // 2인데 카운트 값이 0이나 1이면 -1을 출력한다
            case 2 :
                if (count < 2) {
                    System.out.println(-1);
            // 아니면 카운트에 2를 더한다(5대신 3을2개 더 사용)
                } else {
                    System.out.println(count+2);
                }
                break;
            // 4인데 카운트가 0이라면 -1을 출력한다
            case 4 :
                if (count < 1) {
                    System.out.println(-1);
                //아니면 카운트에 2를 더한다(5대신 3을2개 더 사용)
                } else {
                    System.out.println(count+2);
                }
                break;
        }
    }
    
}

뇌가 퇴행했나?!
수첩에 써보니까 12이상부터는 규칙이 반복되는 것 같다.
1부터 20정도까지 수첩에 쓰면서 생각해보면 쉽다.
파이썬으로 다시 작성해보자

제출 답안

sugar = int(input())
remainder = sugar % 5

if remainder == 0:
    print(sugar//5)
if remainder == 1 or remainder ==3:
    print(sugar//5 +1)
if remainder == 2:
    if sugar//5 < 2:
        print(-1)
    else:
        print(sugar//5 +2)
if remainder == 4:
    if sugar//5 < 1:
        print(-1)       
    else:
        print(sugar//5 +2)

잘 작동하지만 뭔가 찜찜한 풀이이다.

다른 풀이

n = int(input())
i = 0
if(n%5 == 0):
    print(n//5)
elif(n==1 or n==2 or n==4 or n==7):
    print(-1)
    #1,2,4,7이 남으면 나누어떨어지지 않는다
else:
    while(n>0):
        i = i+1 #i는 3kg봉지 갯수
        n = n-3 #총 설탕에서 3kg뺀다
        if(n%5 == 0): #5로 나눠질때까지 반복
            j = int(n/5)#j는 5kg봉지 갯수 
            print(j+i)
            break

반복문 안의 while문에서 3을 계속 빼는 발상이 좋다.
그런데 while에서 3을 계속 빼도 5로 나눠지지 않으면 elif로 가는건가..? 잘 모르겠다.

다른 블로그에서 풀이를 찾아보았다.

  1. 5로 나눌 수 있으면 나눈다.
  2. 5로 못나누면 입력값에서 3을 빼고 count를 올린다.
  3. 1,2번을 반복하는데 만약 5로 못나누고 계속 3을 빼면서 입력값이 0보다 작아진다면 -1를 리턴해준다.

이 아이디어는 “5로 나눌 수 있으면 무조건 나눠라”가 핵심 아이디어이다. 아래 소스 코드를 확인해보자.
출처 : 폴로러브 블로그

모범 답안

n = int(input())
count =0

while True:
  if n%5==0:
    count = count + n//5
    print(box)
    break
  else :
    n = n-3
    count +=1
  if n<0:
    print(-1)
    break

주요 포인트 및 생각해볼 점

코드를 쓰기전에 예외들을 포함한 풀이과정을 곰곰히 생각해봐야겠다.

백준 2292 벌집

|

문제 설명

벌집

위의 그림과 같이 육각형으로 이루어진 벌집이 있다. 그림에서 보는 바와 같이 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를 주소로 매길 수 있다. 숫자 N이 주어졌을 때, 벌집의 중앙 1에서 N번 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나가는지(시작과 끝을 포함하여)를 계산하는 프로그램을 작성하시오. 예를 들면, 13까지는 3개, 58까지는 5개를 지난다.

사고 과정

{1}, {2…7}, {8…19}, {20…37}, {38…61}, {62…} 벌집이 이렇게 규칙적으로 6개씩 늘어나므로 6*cnt cnt+=1 해서 while문을 돌려보자

제출답안

n = int(input())
cnt = 1
while n > 1:
    n -= (6 * cnt)
    cnt += 1
print(cnt)

주요 포인트 및 생각해볼 점

설탕배달하고 실패율 풀 때 되도록 혼자 풀려고 했더니 너무 오래 걸렸어서 앞으로는 풀이과정만 머릿 속에서 정리되면 몇 번 써보고 검색을 해서 좀 더 빠르게 넘어가야겠다.

백준 1712 손익분기점

|

백준 - 손익분기점

문제 설명

월드전자는 노트북을 제조하고 판매하는 회사이다. 노트북 판매 대수에 상관없이 매년 임대료, 재산세, 보험료, 급여 등 A만원의 고정 비용이 들며, 한 대의 노트북을 생산하는 데에는 재료비와 인건비 등 총 B만원의 가변 비용이 든다고 한다.

예를 들어 A=1,000, B=70이라고 하자. 이 경우 노트북을 한 대 생산하는 데는 총 1,070만원이 들며, 열 대 생산하는 데는 총 1,700만원이 든다.

노트북 가격이 C만원으로 책정되었다고 한다. 일반적으로 생산 대수를 늘려 가다 보면 어느 순간 총 수입(판매비용)이 총 비용(=고정비용+가변비용)보다 많아지게 된다. 최초로 총 수입이 총 비용보다 많아져 이익이 발생하는 지점을 손익분기점(BREAK-EVEN POINT)이라고 한다.

A, B, C가 주어졌을 때, 손익분기점을 구하는 프로그램을 작성하시오.

사고 과정

a, b, c = map(int,input().split()) 
if b >= c:
    print(-1)        
else:
    print(int(a//(c-b)+1))

주요 포인트 및 생각해볼 점

처음에는 (math.ceil(a/(c-b))) 올림 함수를 쓰려고 했는데 int를 붙이고(소수점 버림) 1을 더해주면 쓰지 않아도 된다.

파이썬 프로젝트 틱택토

|

틱택토 게임을 만들어보자!
9칸을 그리고 두 명이서 O,X를 차례대로 그려서 먼저 빙고하는 사람이 이기는 게임이다. 유투브 Python for absolute beginners 2019 - TIC TAC TOE project 를 보고 따라 만들었다.

먼저 구조를 짜보자

구조

#보드
#보드판
#게임 시작
#턴 처리하기
#게임이 계속 진행중인지 끝났는지 확인
    #이겼는지 확인
        #가로 확인
        #세로 확인
        #대각선 확인
    #비겼는지 확인
#플레이어 바꾸기

각 구조별로 기본 코드를 넣어보자

보드

board = ["-","-","-",
         "-","-","-",
         "-","-","-"]

보드판

def display_board():
  print("\n")
  print(board[0] + " | " + board[1] + " | " + board[2] + "     1 | 2 | 3")
  print(board[3] + " | " + board[4] + " | " + board[5] + "     4 | 5 | 6")
  print(board[6] + " | " + board[7] + " | " + board[8] + "     7 | 8 | 9")
  print("\n")

게임 플레이

def play_game():
    #첫 보드 보여주기 
    display_board()

턴 처리하기

def handle_turn():
    position = input("1-9중에 표시할 자리를 입력하세요 : ")
    #수를 입력받는다
    position = int(position) - 1
    #index가 0부터 시작하므로 1빼주기
    
    board[position] = "X"
    #입력받은 수 빼기1 인덱스의 -를 X로 바꾼다
    display_board()

여기까지 멈추고 코드를 복사 붙여넣기해서 한 번 돌려보면 내가 입력한 숫자에 해당하는 판에 X자가 표시되는 화면을 볼 수 있다.

틱택토 게임화면

게임 플레이

def play_game():
    #첫 보드 보여주기 
    display_board()
        
    #"게임이 아직 진행중" 변수가 사실일 동안에    
    while game_still_going:
        #현재 플레이어의 턴을 실행하고
        handle_turn(current_player)
        #게임이 끝났는지 확인하고
        check_if_game_over()
        #플레이어를 바꾼다
        flip_player()

게임이 계속 진행중인지 확인

def check_if_game_over():
    #게임이 끝났는지 볼 수 있는 방법은 무엇이 있을까?
    check_for_winner()
    #누가 이겼거나
    check_if_tie()
    #이긴 사람 없이 판이 꽉 찼거나

이겼는지 비겼는지 확인

def check_for_winner():
    #가로 확인
    #세로 확인
    #대각선 확인
    return
def check_if_tie():
    return

플레이어 바꾸기

def flip_player():
    return

이정도 쓰고 에러가 없는지 돌려보면,
game_still_going 변수가 정의되지 않았다고 나온다.
이 변수는 여기저기서 사용될 수 있으니까 전역 변수(global bariables)로 정의한다.
맨 위에 필요한 전역 변수들을 넣어주자.

보드

#------- 전역 변수 -------

# 게임 보드
board = ["-","-","-",
         "-","-","-",
         "-","-","-"]
# 게임이 계속 진행중이라면
game_still_going = True

# 누가 이겼나? 비겼나?
winner = None

# 누구 차례인가?
current_player = "X"

게임플레이로 가서 게임이 끝났을 때 승자를 출력하는 코드를 넣어보자.

게임 플레이

def play_game(): 
    display_board()
        
    while game_still_going:

        handle_turn(current_player)

        check_if_game_over()

        flip_player()

    #게임이 끝났으면
    if winner == "X" or winner == "O":
        print("우승자는"+ winner+"!")
    elif winner == None:
        print("비겼습니다.")

이겼는지 비겼는지 확인하는 부분에
가로 확인, 세로 확인, 대각선 확인 함수를 넣고
누군가 이기면 승자를 출력하고 game_still_going 변수를 거짓으로 바꾸자.

이겼는지 확인

def check_for_winner():
    #전역변수를 함수 안에서 가져다 사용하려면 선언해줘야한다 
    global winner

    #가로 확인
    row_winner = check_rows()
    #세로 확인
    column_winner = check_columns()
    #대각선 확인
    diagonal_winner = check_diagonals()
    if row_winner:
        winner = row_winner
    elif column_winner:
        winner = column_winner
    elif diagonal_winner:
        winner = diagonal_winner
    else:
        winner = None
    return

def check_rows():
    #전역변수 선언
    global game_still_going
    #첫째줄의 값 "-" 가 아니고 모두 같다면 row_1이 true가 된다
    row_1 = board[0] == board[1] == board[2] != "-"
    row_2 = board[3] == board[4] == board[5] != "-"
    row_3 = board[6] == board[7] == board[8] != "-"
    # 세 줄 중에 하나라도 트루면 게임 끝
    if row_1 or row_2 or row_3:
        game_still_going = False
    # 우승자 반환 
    if row_1:
        return board[0]
    elif row_2:
        return board[3]
    elif row_3:
        return board[6]

def check_columns():
    global game_still_going
    column_1 = board[0] == board[3] == board[6] != "-"
    column_2 = board[1] == board[4] == board[7] != "-"
    column_3 = board[2] == board[5] == board[8] != "-"
    if column_1 or column_2 or column_3:
        game_still_going = False
    if column_1:
        return board[0]
    elif column_2:
        return board[1]
    elif column_3:
        return board[2]

def check_diagonals():
    global game_still_going
    diagonals_1 = board[0] == board[4] == board[8] != "-"
    diagonals_2 = board[6] == board[4] == board[2] != "-"
    if diagonals_1 or diagonals_2:
        game_still_going = False
    if diagonals_1:
        return board[0]
    elif diagonals_2:
        return board[6]

플레이어를 바꾸는 함수를 넣어보자

플레이어 바꾸기

def flip_player():
    global current_player
    if current_player == "X":
        current_player = "O"
    elif current_player == "O":
        current_player = "X"

비겼는지 확인

def check_if_tie():
    global game_still_going
    #보드판에 더이상 -가 남아있지 않으면 게임 끝
    if "-" not in board:
        game_still_going = False

입력 예외처리정도를 제외하고 이제 거의 다 만들었다! 입력 예외처리를 추가하자

턴 처리하기

def handle_turn(player):
    #if 대신 while을 써줘야 유효값이 들어올 때까지 계속해서 물어보게된다
    while position not in ["1","2","3","4","5","6","7","8","9"]:
        position = input("유효하지 않은 입력값입니다. 1과 9중의 수를 입력해주세요")

여기서 프로그램을 돌려보면, 이미 X친 자리에 다시 O를 넣어도 O가 들어가는걸 볼 수 있다. 이걸 방지하기 위한 코드를 넣어보자.

def handle_turn(player):
    if board[position] != "-":
        print("이미 표시된 자리입니다")

이걸 합쳐서 잘 써보면

 처리하기
def handle_turn(player):

    print(player + "의 턴입니다")
    position = input("1-9중에 표시할 자리를 입력하세요 : ")

    valid = False
    while not valid:

        while position not in ["1","2","3","4","5","6","7","8","9"]:
            position = input("유효하지 않은 입력값입니다. 1과 9중의 수를 입력해주세요")
    
        position = int(position) - 1    
    
        if board[position] == "-":
            valid = True
        else:
            print("이미 표시된 자리입니다")

    board[position] = player

    display_board()

틱택토 게임화면2

게임 만들기가 완료되었다~!!!

최종 전체 코드


#------- 전역 변수 -------

# 게임 보드
board = ["-","-","-",
         "-","-","-",
         "-","-","-"]
# 게임이 계속 진행중이라면
game_still_going = True

# 누가 이겼나? 비겼나?
winner = None

# 누구 차례인가?
current_player = "X"

def display_board():
    print("\n")
    print(board[0] + " | " + board[1] + " | " + board[2] + "     1 | 2 | 3")
    print(board[3] + " | " + board[4] + " | " + board[5] + "     4 | 5 | 6")
    print(board[6] + " | " + board[7] + " | " + board[8] + "     7 | 8 | 9")
    print("\n")

#보드판
def play_game():
    #첫 보드 보여주기 
    display_board()
    handle_turn(current_player)

#턴 처리하기
def handle_turn(player):

    print(player + "의 턴입니다")
    position = input("1-9중에 표시할 자리를 입력하세요 : ")

    valid = False
    while not valid:

        while position not in ["1","2","3","4","5","6","7","8","9"]:
            position = input("유효하지 않은 입력값입니다. 1과 9중의 수를 입력해주세요")
    
        position = int(position) - 1    
    
        if board[position] == "-":
            valid = True
        else:
            print("이미 표시된 자리입니다")

    board[position] = player

    display_board()

#게임 플레이
def play_game():
    #첫 보드 보여주기 
    display_board()

    #"게임이 아직 진행중" 변수가 사실일 동안에    
    while game_still_going:
        
        #현재 플레이어의 턴을 실행하고
        handle_turn(current_player)
        
        #게임이 끝났는지 확인하고
        check_if_game_over()
        
        #플레이어를 바꾼다
        flip_player()
        
    #게임이 끝났으면
    if winner == "X" or winner == "O":
        print("우승자는"+ winner+"!")
    elif winner == None:
        print("비겼습니다.")

# 게임이 계속 진행중인지 확인
def check_if_game_over():
    #게임이 끝났는지 볼 수 있는 방법은 무엇이 있을까?
    check_for_winner()
    #누가 이겼거나
    check_if_tie()
    #이긴 사람 없이 판이 꽉 찼거나

def check_for_winner():
    #전역변수를 함수 안에서 가져다 사용하려면 선언해줘야한다 
    global winner

    #가로 확인
    row_winner = check_rows()
    #세로 확인
    column_winner = check_columns()
    #대각선 확인
    diagonal_winner = check_diagonals()
    if row_winner:
        winner = row_winner
    elif column_winner:
        winner = column_winner
    elif diagonal_winner:
        winner = diagonal_winner
    else:
        winner = None

def check_rows():
    #전역변수 선언
    global game_still_going
    #첫째줄의 값 "-" 가 아니고 모두 같다면 row_1이 true가 된다
    row_1 = board[0] == board[1] == board[2] != "-"
    row_2 = board[3] == board[4] == board[5] != "-"
    row_3 = board[6] == board[7] == board[8] != "-"
    # 세 줄 중에 하나라도 트루면 게임 끝
    if row_1 or row_2 or row_3:
        game_still_going = False
    # 우승자 반환 
    if row_1:
        return board[0]
    elif row_2:
        return board[3]
    elif row_3:
        return board[6]

def check_columns():
    global game_still_going
    column_1 = board[0] == board[3] == board[6] != "-"
    column_2 = board[1] == board[4] == board[7] != "-"
    column_3 = board[2] == board[5] == board[8] != "-"
    if column_1 or column_2 or column_3:
        game_still_going = False
    if column_1:
        return board[0]
    elif column_2:
        return board[1]
    elif column_3:
        return board[2]

def check_diagonals():
    global game_still_going
    diagonals_1 = board[0] == board[4] == board[8] != "-"
    diagonals_2 = board[6] == board[4] == board[2] != "-"
    if diagonals_1 or diagonals_2:
        game_still_going = False
    if diagonals_1:
        return board[0]
    elif diagonals_2:
        return board[6]

def check_if_tie():
    global game_still_going
    #보드판에 더이상 -가 남아있지 않으면 게임 끝
    if "-" not in board:
        game_still_going = False

def flip_player():
    global current_player
    if current_player == "X":
        current_player = "O"
    elif current_player == "O":
        current_player = "X"

# ------------ 게임 시작 -------------

play_game()

프로그래머스 level 1 실패율, Lambda

|

실패율

문제 설명

슈퍼 게임 개발자 오렐리는 큰 고민에 빠졌다. 그녀가 만든 프랜즈 오천성이 대성공을 거뒀지만, 요즘 신규 사용자의 수가 급감한 것이다. 원인은 신규 사용자와 기존 사용자 사이에 스테이지 차이가 너무 큰 것이 문제였다.

이 문제를 어떻게 할까 고민 한 그녀는 동적으로 게임 시간을 늘려서 난이도를 조절하기로 했다. 역시 슈퍼 개발자라 대부분의 로직은 쉽게 구현했지만, 실패율을 구하는 부분에서 위기에 빠지고 말았다. 오렐리를 위해 실패율을 구하는 코드를 완성하라.

실패율은 다음과 같이 정의한다. 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수 전체 스테이지의 개수 N, 게임을 이용하는 사용자가 현재 멈춰있는 스테이지의 번호가 담긴 배열 stages가 매개변수로 주어질 때, 실패율이 높은 스테이지부터 내림차순으로 스테이지의 번호가 담겨있는 배열을 return 하도록 solution 함수를 완성하라.

입출력 예

n stages result
5 [2, 1, 2, 6, 2, 4, 3, 3] [3,4,2,1,5]
4 [4,4,4,4,4] [4,1,2,3]

사고 과정

def solution(n, stages):
    
    list_n = range(1,n+1)
    fail_rates = []
    failed_user = 0 # 실패한 사람의 수
    total_user = len(stages) 
    #전체 사용자의 수 : 실패한 사람들을 빼서 스테이지에 도달한 사람의 수로 사용    
    
    for n in list_n:
        if total_user == 0:
            #전체 사용자가 0이면 실패율0
            fail_rates.append(0)
        else:
            failed_user = stages.count(n)
            # 실패한 사람의 수 : 스테이지 배열에서 n의 갯수
            fail_rates.append(failed_user/total_user * 100)
            # 실패율 : 실패한 사람들의 수 / 스테이지에 도달한 사람의 수 * 100
            total_user -= failed_user
            # 전체 사용자의 수에서 실패한 사람들의 수를 뺀다
    print(fail_rates)
    # (1, 12.5)로 출력되는걸 보니 튜플로 만들어진건가??!!
    
    pair = list(zip(list_n, fail_rates))
    # 1부터N까지의 리스트와 fail_rates리스트를 대응해서 딕셔너리로 만들고 리스트에 넣는다.
    # 여기까지 출력하면 : [(1, 12.5), (2, 42.857142857142854), (3, 50.0), (4, 50.0), (5, 0.0)]  
    pair_sorted = sorted(pair, key= lambda x : dict[x], reverse=True)
    # 밸류인 실패율을 기준으로 내림차순 정렬하고 키값을 반환한다. 여기서 에러발생
    print(pair_sorted)
    return pair_sorted 

이 딕셔너리를 밸류 값 기준으로 내림차순 정렬하고 키값을 반환하려면
아래와 같이 람다라는걸 사용해야 되는 것 같다.

sorted(딕셔너리이름, key= lambda x : dict[x])

실행했더니 타입에러가 난다.
TypeError: ‘<’ not supported between instances of ‘types.GenericAlias’ and ‘types.GenericAlias’
자료형에 대한 에러가 나는 것 같으니 모범답안처럼 자료형을 바꿔보았다.

제출 답안

def solution(n, stages):
    
    list_n = range(1,n+1)
    fail_rates = {}
    # []는 빈 배열을 만들고 {}는 빈 딕셔너리를 만든다.
    failed_user = 0 
    total_user = len(stages)     
    
    for n in list_n:
        if total_user == 0:
            fail_rates[n] = 0
        else:
            failed_user = stages.count(n)
            fail_rates[n] = failed_user/total_user
            total_user -= failed_user
    return sorted(fail_rates,key=lambda x : fail_rates[x], reverse=True)

드디어 성공..!!! 반나절이 걸렸다..!!
3일 쉬고 다시 써보라고하면 못 쓸것 같다. 매일 공부하고 반복 학습을 해야지!

모범 답안

def solution(N, stages):
    fail_rate = {}
    total_user = len(stages)

    for stage in range(1, N+1):
        if total_user != 0:
            fail_user = stages.count(stage)
            fail_rate[stage] = fail_user / total_user
            #여기서는 zip이 아닌 arr1[arr2]를 사용했다
            total_user -= fail_user
        else:
            fail_rate[stage] = 0

    return sorted(fail_rate, key=lambda x : fail_rate[x], reverse=True)

모범 답안2

def solution(N, stages):
    result = {}
    denominator = len(stages)
    for stage in range(1, N+1):
        if denominator != 0:
            count = stages.count(stage)
            result[stage] = count / denominator
            denominator -= count
        else:
            result[stage] = 0
    return sorted(result, key=lambda x : result[x], reverse=True)

이 부분은 내일 다시 살펴봐야겠다.

질문

fail_rates = [] 이렇게 딕셔너리로 만들었었는데
print(fail_rates)
이 부분이 (1, 12.5)로 출력되는걸 보니 튜플로 만들어져서 에러가 난걸까?

주요 포인트 및 생각해볼 점

-arr1[arr2]로 딕셔너리를 만드는 방법
-파이썬 딕셔너리 정렬하기

파이썬에서 (), {}, []의 차이점

  arr = [] # 빈 배열을 만들 때 []사용  
  arr = [1,2,3,4] #원소가 있는 배열을 만들 때 []사용  
  arr[3] #배열의 3번째 원소에 접근할 때 []사용  

  mytuple = () #빈 튜플 생성할 때 ()사용  
  mytuple = (1,2,3,4) # 원소가 있는 튜플을 만들 때 ()사용  
  mytuple[3] # 튜플의 원소에 접근할 때 []사용  

  mydictionary = {} #빈 딕셔너리 생성 시 {}사용  
  mydictionary = {"mouse":3, "penguin":5}  
  mydictionary["mouse"] # key("mouse")에 대응하는 value(3)에 접근할 때 사용  
  mydictionary["cat"] = 1 # key("cat")에 대한 value(1) 생성  

출처: 해시코드 - () [] {}의 차이와 사용해야 할 곳

프로그래머스 level 1 음양 더하기

|

음양 더하기

문제 설명

어떤 정수들이 있습니다. 이 정수들의 절댓값을 차례대로 담은 정수 배열 absolutes와 이 정수들의 부호를 차례대로 담은 불리언 배열 signs가 매개변수로 주어집니다. 실제 정수들의 합을 구하여 return 하도록 solution 함수를 완성해주세요.

입출력 예

absolutes signs result
[4,7,12] [true,false,true] 9
[1,2,3] [false,false,true] 0

사고 과정

def solution(absolutes, signs):
    return sum([signs[i] * absolutes[i] for i in zip(absolutes, signs)])

i 가 정의되지 않았다고 에러가 떠서 실행되지 않았다.

모범 답안

def solution(absolutes, signs):
    answer=0
    for absolute,sign in zip(absolutes,signs):
        if sign:
            answer+=absolute
        else:
            answer-=absolute
    return answer

곱할 필요 없이 더하기빼기를 사용했으면 되었다.

모범 답안2

def solution(absolutes, signs):
    return sum(absolutes if sign else -absolutes for absolutes, sign in zip(absolutes, signs))

나도 sign을 있는 그대로 부호로 쓰고싶었다..!

주요 포인트 및 생각해볼 점

for a,b in zip(a,b)를 다음 번에는 잘 써봐야겠다.

프로그래머스 level 1 내적

|

내적

문제 설명

길이가 같은 두 1차원 정수 배열 a, b가 매개변수로 주어집니다. a와 b의 내적을 return 하도록 solution 함수를 완성해주세요.

이때, a와 b의 내적은 a[0]b[0] + a[1]b[1] + … + a[n-1]*b[n-1] 입니다. (n은 a, b의 길이)

입출력 예

a b result
[1,2,3,4] [-3,-1,0,2] 3
[-1,0,1] [1,0,-1] -2

제출 답안

def solution(a, b):
    ans = 0
    for i in range(0,len(a)):
        ans += a[i]*b[i]
    return ans

한 번에 정답이 떠서 뿌듯했다.

모범 답안

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

주요 포인트 및 생각해볼 점

인자 두 개를 받아서 zip을 이용해서 결과를 출력하다니 나도 저렇게 써봐야겠다.

프로그래머스 level 1 두 개 뽑아서 더하기(itertools - combinations)

|

두 개 뽑아서 더하기

문제 설명

정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요.

입출력 예

numbers result
[2,1,3,4,1] [2,3,4,5,6,7]
[5,0,2,7] [2,5,7,9,12]

사고 과정

def solution(numbers):
    for i in numbers:
        for j in numbers:
            numbers.append(i+j)
    return set(numbers)

반복문을 두 겹으로 돌리면 되겠지라고 생각했는데 실행시간이 10초를 넘겨서 처리되지 않았다. 어딘가 잘못 된 것 같은데 이렇게 풀려면 아래처럼 작성했어야 했다.

def solution(numbers):
    answer = []
    for i in range(len(numbers)):
        for j in range(i+1, len(numbers)): 
            #i+1을 쓰면 서로 다른 두 수가 되나?
            if numbers[i]+numbers[j] not in answer:
                answer.append(numbers[i]+numbers[j])
    answer.sort()
    return answer

인터넷에 찾아보니 이런 내장함수가 있었다.

from itertools import combinations
def solution(numbers):
    answer = set()
    for i in list(combinations(numbers,2)):
        answer.add(sum(i))
    return sorted(answer)

파이썬 기본 라이브러리인 itertools의 combinations 라는 내장함수를 사용하여 인자값에 따라 해당 요소로 구할수 있는 모든 조합을 리턴한다.
ex) combinations(numbers, 2)는 numbers 리스트 안에 2개의 요소로 구할 수 있는 모든 조합을 반환한다.

모범 답안

from itertools import combinations
def solution(numbers):
    return sorted(list(set([sum([i,j]) for i,j in combinations(numbers,2)])))

주요 포인트 및 생각해볼 점

내장함수를 이용하면 수학적인 부분을 더 쉽게 해결할 수 있다.