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

 

프로그래머스

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

programmers.co.kr

 

풀이

조건에 맞춰서 차근차근 구현만 하면 되는 문제였다.

파이썬 내 올림 기능을 지원하는 메소드가 math.ceil 인데 실수로 반올림하는 round() 메서드를 썼다... 주의하자!

 

먼저 수도코드로 쭉 작성한 뒤 구현했고, 바로 통과됬다.

 

1. records 내 값을 공백 기준으로 split해서 time, car_num, inout에 넣기

2. 딕셔너리에 car_num을 키로 time 넣어주기. 각 딕셔너리 value값은 배열. (in, out 순서로 들어간다)

 * 만약 배열 길이가 홀수면 출차 내역이 입력되지 않은 요소이므로 23:59를 직접 넣어준다

3. records 배열 순회가 끝나면 딕셔너리를 살펴보면서 시간을 계산한다.

 - [짝수] : IN / [홀수] : OUT 이므로 홀수 - 짝수 해주면 된다.

   인자를 받아올 때 ":"를 기준으로 hour, min을 쪼개주었다.

   시간은 상관없는데 분은 음수값이 나왔을 때 예외처리를 해주자. (hour -= 1, min += 60)

 

4. 총 누적시간이 기본 시간을 넘는다면 문제 조건대로 계산하고, 넘지 않는다면 기본 요금을 저장한다.

 * 여기에서 문제 조건 상 차량번호가 작은 요소부터 출력해달라고 했으므로 [차량번호, 요금] 을 저장하는 배열을 만들어준 뒤 차량번호를 기준으로 정렬한 뒤 요금값을 차례대로 answer에 넣어주자.

 

40분 정도 소요됬다!

 

python 코드

import math
def solution(fees, records):
    carnum_fee = [] # (차량번호, 요금) 순 저장
    car_dict = {}
    
    for r in records:
        time, car_num, inout = r.split(" ")
        if car_num in car_dict:
            car_dict[car_num].append(time)
        else:
            car_dict[car_num] = [time]
    
    
    for k in car_dict.keys():
        # 출차 기록이 없는 경우
        if len(car_dict[k]) % 2 != 0:
            car_dict[k].append("23:59")
        
        # 시간 계산
        total_time = 0
        for i in range(0, len(car_dict[k]), 2):
            # OUT : i+1, IN : i
            out_h, out_m = map(int,car_dict[k][i+1].split(":"))
            in_h, in_m = map(int, car_dict[k][i].split(":"))
            
            hour = out_h - in_h
            minute = out_m - in_m
            
            if minute < 0:
                hour -= 1
                minute += 60
            
            total_time += hour * 60 + minute

        # 요금 계산
        if total_time > fees[0]:
            carnum_fee.append([k, fees[1] + math.ceil((total_time-fees[0]) / fees[2]) * fees[3]])
        else:
            carnum_fee.append([k, fees[1]])
    
    carnum_fee.sort(key = lambda x : x[0])
    
    answer = [v[1] for v in carnum_fee]
    return answer

이때까진 행복했지...

본선 들어가서 진짜 열심히 5일간 달리고 연습용으로 만든 AWS 계정에서 과금도 발생하고 ^^ 우여곡절이 많았는데 우리 서비스는 아직 부족했나보다.

 

오배송 관련 문제를 처리해주는 앱 2개를 개발해서 제출했는데 월요일 오후에 온다던 결과가 아침 9시에 와서 아침부터 눈물의 런닝을 하고 왔다. 

 

그치.. 감사하다는 멘트로 시작하면 떨어진거지.... 메일 제목만 보고 직감했다 엉엉

 

개발자... 꼭 되어야지 

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

 

프로그래머스

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

programmers.co.kr

 

풀이

진법변환, 소수판별은 자주 등장하는 부분이라 비교적 쉽게 구현했다. 소수의 판별 조건이 약간 까다로웠는데 가능한 시나리오들을 차근차근 생각해봤다.

 

1. 진법변환

2. 앞에서부터 살펴보는데

 1) 맨 앞인 경우 -> P0, P 케이스가 등장할 수 있다.

    - P0 : 뒷 숫자에서 0이 등장하는 경우, 그 앞까지의 숫자가 소수인지 체크

    - P : 숫자 끝까지 0이 등장하지 않는 경우, 해당 숫자 자체가 소수인지 체크

 2) 0이 한번이라도 등장한 경우 -> 0P0, 0P 케이스가 등장할 수 있다.

   - 0P0 : 0이 한번 더 등장한 경우, 0과 0 사이의 숫자가 소수인지 체크

   - 0P : 숫자 끝까지 0이 한번 더 등장하지 않은 경우, 0 뒤의 숫자가 소수인지 체크

 

따라서 가능한 경우를 flag로 만들어서 체크해줘야 할 때마다 체크해줬다. 요즘 디버깅 안하고 프로그래머스 내에서 최대한 풀어보려고 하다 보니 print 문을 섞어서 실행했다. 두가지 버전 모두 기록해두려고 한다!

 

주의할 점은 소수인지 체크할 숫자를 담는 문자열이 빈 문자열인 경우 소수 체크를 하지 않고 넘어가줘야 한다. (코드 내 check_num != '' 조건)

ex. P0 경우가 등장하여 check_num이 빈 문자열로 초기화되었는데 그 뒤에 다시 0이 등장하면 빈 문자열이 isPrime 함수로 넘어가 형변환 에러가 발생한다. 

 

중간에 10분정도 쉬다가 다시 풀었는데 한 1시간정도 걸렸다.

 

python 코드 (print 출력문 O)

# 진법 변환
def convert(n, k):
    result = ''
    q, r = divmod(n, k)
    result += str(r)
    
    while q != 0:
        q, r = divmod(q, k)
        result += str(r)
    
    return result[::-1]

# 소수 판별 (제곱근까지만 판단)
def isPrime(num):
    if num == 0 or num == 1:
        return False
    for i in range(2, int(num**0.5)+1):
        if num % i == 0:
            # 소수 아님
            return False    
    return True

def solution(n, k):
    answer = 0
    
    converted_n = convert(n, k)
    
    check_num = ''
    
    flag_0P0 = False
    flag_P0 = False
    flag_0P = False
    flag_P = False
    
    for i in range(len(converted_n)):
        print("------")
        print(flag_0P0,flag_P0,flag_0P,flag_P)
        print(check_num)
        print("------")
        
        # 맨 앞인 경우
        if i == 0:
            # P0, P 가능
            check_num += converted_n[i]
            flag_P, flag_P0 = True, True
            continue
        
        if converted_n[i] == '0':
            flag_P = False
            flag_0P = True
            # 만약 맨앞에서부터 보던 중이었다면
            if flag_P0:
                print("PO case", check_num)
                if isPrime(int(check_num)):
                    print("PO Hit", check_num)
                    answer += 1
                check_num = ''
                flag_0P0, flag_P0 = True, False
                continue
            
            # 한번이라도 0이 등장한 적이 있다면
            elif flag_0P0 and check_num != '':
                print("0PO case", check_num)
                if isPrime(int(check_num)):
                    print("0PO Hit", check_num)
                    answer += 1
                check_num = ''
        else:
            check_num += converted_n[i]
        
    
    # 맨 뒤까지 다 봤는데 0이 안나온 경우였다면, P 경우 체크
    if flag_P and check_num != '' and isPrime(int(check_num)) :
        answer += 1
        print("P Hit", check_num)
    # 맨 뒤까지 다 봤고 0P가 가능한 경우
    if flag_0P and check_num != '' and isPrime(int(check_num)) :
        answer += 1
        print("0P Hit", check_num)
        
    return answer

 

python 코드 (깔끔 ver)

# 2022-09-20
# 2022 카카오 테크 인턴십 기출 - k진수에서 소수 개수 구하기 (프로그래머스 lv2)
# https://school.programmers.co.kr/learn/courses/30/lessons/92335
# 소요 시간 : 15:17 ~ 16:06, 16:21~16:31 (60m)

# 진법 변환
def convert(n, k):
    result = ""
    q, r = divmod(n, k)
    result += str(r)

    while q != 0:
        q, r = divmod(q, k)
        result += str(r)

    return result[::-1]


# 소수 판별 (제곱근까지만 판단)
def isPrime(num):
    if num == 0 or num == 1:
        return False
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            # 소수 아님
            return False
    return True


def solution(n, k):
    answer = 0

    converted_n = convert(n, k)

    check_num = ""

    flag_0P0 = False
    flag_P0 = False
    flag_0P = False
    flag_P = False

    for i in range(len(converted_n)):
        # 맨 앞인 경우
        if i == 0:
            # P0, P 가능
            check_num += converted_n[i]
            flag_P, flag_P0 = True, True
            continue

        if converted_n[i] == "0":
            flag_P = False
            flag_0P = True
            # 만약 맨앞에서부터 보던 중이었다면
            if flag_P0:
                if isPrime(int(check_num)):
                    answer += 1
                check_num = ""
                flag_0P0, flag_P0 = True, False
                continue

            # 한번이라도 0이 등장한 적이 있다면
            elif flag_0P0 and check_num != "":
                if isPrime(int(check_num)):
                    answer += 1
                check_num = ""
        else:
            check_num += converted_n[i]

    # 맨 뒤까지 다 봤는데 0이 안나온 경우였다면, P 경우 체크
    if flag_P and check_num != "" and isPrime(int(check_num)):
        answer += 1
    # 맨 뒤까지 다 봤고 0P가 가능한 경우
    if flag_0P and check_num != "" and isPrime(int(check_num)):
        answer += 1

    return answer

 

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

 

프로그래머스

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

programmers.co.kr

 

풀이

두 큐의 합을 같게 만들어주려면, 합이 더 큰 큐에서 pop해가면서 중간값을 맞춰봐야 최소횟수.

이 과정에서 완전히 빈 큐가 생겨버리면 두 큐의 합을 같게 만들 수 없는 것이므로 -1을 리턴해주면 된다.

로직 자체는 맞게 접근한 것 같은데 테스트케이스 몇개가 계속 시간초과가 나서 파이썬 메서드의 시간복잡도를 봤더니 답이 나왔다.

 

배열의 가장 앞의 요소를 pop해주기 위해 배열 자료형의 pop(0) 메서드를 사용했는데, pop() 연산 자체는 복잡도가 O(1)인데 pop(0)은 O(n)이다. 그 이유는 맨 앞에 있는 값을 출력해주기 위해 전체 복사를 하기 때문이다..! 따라서 리스트 말고 deque를 사용하여 pop(0) 대신 popleft()를 사용하는 것이 시간복잡도 상 매우 유리하다.

 

자료형을 list -> deque로 바꾸고 테스트케이스 22~24번이 해결됬으며,

최대 가능한 횟수를 모든 요소끼리 서로 다 바꿔도 안될 때 (리스트의 최대길이만큼 교환했을 때) 300,000번으로 제한해두니 테스트케이스 11, 28번이 해결되었다.

 

sum() 메서드와 len() 메서드 역시 매번 연산해줄 필요는 없어서 산술연산만 할 수 있게 코드를 약간 길게 적었다.

 

방향은 맞게 잡았는데 시간복잡도에서 30분은 더 쓴 듯 하다.

 

python 코드

from collections import deque
def solution(queue1, queue2):
    answer = 0
    
    deque1 = deque(queue1)
    deque2 = deque(queue2)
    
    sum1 = sum(queue1)
    sum2 = sum(queue2)
    
    len1 = len(queue1)
    len2 = len(queue2)
    
    goal = (sum1 + sum2) / 2
    
    while len1 != 0 and len2 != 0:
        if sum1 == goal and sum2 == goal:
            return answer
        
        if answer > 300000:
            break
            
        if sum1 > sum2:
            value = deque1.popleft()
            deque2.append(value)
            sum1 -= value
            sum2 += value
            len1 -= 1
            len2 += 1
        elif sum1 < sum2:
            value = deque2.popleft()
            deque1.append(value)
            sum1 += value
            sum2 -= value
            len1 += 1
            len2 -= 1
        else:
            if sum1 == goal and sum2 == goal:
                return answer
            
        answer += 1
    
    answer = -1
            
    return answer

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

 

프로그래머스

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

programmers.co.kr

 

풀이

문제에서 시키는 대로 차근차근 구현하면 되는 문제다.

 

input 이해

survey[i][0] : i+1번 질문 비동의 선택 시 성격유형

survey[i][1] : i+1번 질문 동의 선택 시 성격유형

 

choices[i] : 4로 나눈 몫이 1 이상 : 동의 -> survey[i]의 [1] 유형에 4로 나눈 나머지 점수 부여 ('모르겠음' 선택지는 0점인데 나머지도 0점이라 케이스를 쪼개지 않아도 괜찮음)

choices[i] : 4로 나눈 몫이 1 미만 : 비동의 -> survey[i]의 [0] 유형에 (4 - choices[i]) 점수 부여 

 

지표 체크

각각의 성격유형을 key-value 형태로 저장하는 것이 검색에 수월하여 dictionary 형태를 사용하였다. 다른 사람의 풀이를 보니 많이들 비슷하게 접근했더라.

 

 

lv1이라 좀 수월하게 풀었다

 

python 코드

def solution(survey, choices):
    answer = ''
    
    score = {'R': 0, 'T': 0, 'C' : 0, 'F': 0, 'J': 0, 'M': 0, 'A': 0, 'N': 0}
    
    # 점수 부여
    for i in range(len(choices)):
        # 동의
        if choices[i] // 4 >= 1:
            score[survey[i][1]] += choices[i] % 4
        # 비동의
        else:
            score[survey[i][0]] += (4 - choices[i])
    
    # 지표별 유형 판단
    if score['R'] >= score['T']:
        answer += 'R'
    else:
        answer += 'T'
    
    if score['C'] >= score['F']:
        answer += 'C'
    else:
        answer += 'F'
        
    if score['J'] >= score['M']:
        answer += 'J'
    else:
        answer += 'M'
        
    if score['A'] >= score['N']:
        answer += 'A'
    else:
        answer += 'N'
        
    
    return answer

놀랍게도 이 글을 보고 다시 물욕이 살아나서 이틀 내내 써치했다... 다시 이런 어리석은 짓 하지 않기 위해 기록^^

그만 써치하고 얘네나 쓰자

  • 로이텀 2023 먼슬리
  • 미도리 2023 하루한페이지
  • 무인양품 더블링 노트, 문고본 노트, 1일 1페이지 노트
  • 옥스포드 상철 노트

( 필사하고 싶으면 -> 어프로치 노트 프로 / 로이텀 1917 )

 


 

개발 블로그긴 한데 나는 항상 코드를 적기 전에 쫙 로직을 손으로 직접 다 적은 뒤 코드로 옮기는 습관이 있다. 뭔가 생각은 금방 휘발되는 것 같고, 진짜 급할 때는 컴퓨터 메모장에 적지만 그 외에는 보통 빠른 필기를 위해 만년필과 노트를 애용한다.

 

매번 잊고 만년필 쓰기 좋은 노트를 찾아봐서 이번 기회에 내가 쓰고 좋았던 노트들을 기록해두려 한다.

 

1. 퀄리티는 그냥 그렇지만 가성비가 좋은 노트

  • [PENCO] Soft PP Notebook B6

솔직히 만년필 안번지는 노트 중 디자인 & 가성비 다 잡은 제품이라고 생각한다. 내가 평소 사용하는 만년필은 모두 EF 닙에 라미, 파버카스텔, 카웨코, 세일러 제품으로 다양하다. 잉크가 콸콸 나오는 딥펜은 물론 로디아같은 노트에나 써야겠지만 막 팍팍 넘겨가면서 쓰기에는 어쩐지 아까운 느낌이었는데 이 제품 아주 준수하다. 만년필이랑 궁합이 나쁘지 않음!

 

물론 큰 단점은 노트 등이 본드칠이 되어있는 것 같은데 되게 잘 뜬다. B6 사이즈 외에 A7 사이즈도 스케쥴 관리용으로 썼는데 둘다 등이 뜬 걸로 보아 초반에 쫙쫙 펼쳐쓰면 뜯어지는 듯 하다. 다음데 재구매하면 초반에는 적당히 꺾어 써야곘다 ㅎㅎ

 

 

 

 

 

 

 

 

2. 믿음의 노트 (돈과 교환)

  • 로이텀 (말해모해...) -> 얘는 매년 먼슬리를 구매해서 잘 쓰고 있다. 도트 내지도 마음에 들고 soft 커버를 사면 부들부들하고 무겁지도 않고 아주 좋다. 단점은.. 가격? ㅎ 앗싸리 11월쯤 연말에 미리 구매하든가 2월쯤 늦게 구매해야 저렴헀던 걸로 기억
  • 미도리 (말모22) -> 얘는 트래블러스도 좋았고 그냥 일반 노트도 좋았다. 단점은 일본꺼라는거? 그 외에 표지를 무조건 끼워줘야한다는 점이 아쉽다. 안끼고 다니는 감성도 있겠지만 나는 가방 안에 노트, 노트북, 기타 물건을 와르르 넣어서 다니는 편이라 자꾸 꾸겨지고 그러더라 ... 얘는 일기장으로 참 좋았다

3. 무난했던 노트들

  • 어프로치 노트 -> 얘는 Q&A가면 눈물의 글들을 많이 볼 수 있다. 그리드/도트 내지 출시 계획 있냐는 ... 물론 나도 한번 울고 왔다. 여기 노트 퀄리티가 아주 준수하다. 현재는 라인/무지 두 종류만 있어서 나는 일기장으로 구매했는데 라이트는 저렴한 맛에 만년필 버텨주니까 라인 노트 사서 개발할 때 휘리릭 쓰기 좋을 것 같다. 펼쳐지는 것도 펜코 제품에 비해 안전하게 180도로 펼쳐진다 ㅋㅋ 그리고 표지에 불필요한 로고 하나 없이 깔끔하다!
  • 옥스포드 상철 노트

 

옥스포드 노트들을 많이 써봤는데 몇개가 만년필을 잘 견뎌준다. 그 중 사이즈 적당하게 정착한 노트가 있다. 사진을 첨부했는데 이 노트 아주 괜찮다. 쿠팡에도 입점되어 있어서 나는 필기를 정리해야된다거나 깔끔하게 써야되는 공부를 할 때는 상철 노트를 선호하는데 아주 딱 맞다! 표지도 PP 재질로 튼튼하고 무난한 가격이다. 

 

물론.. 옥스포드는 만년필 못 버텨주는 제품이 많다. 왼쪽 제품 아니면 꽤 많은 제품이 만년필에 거미줄이 좍좍 쳐졌다... (이 제품도 버틴다 정도지 궁합이 좋다, 이건 아님)

 

 

 

 

 

4. 아직 안써봤는데 써보려고 기록하는 노트들

  • 인생상점 불렛저널 -> 이거는 매번 품절이거나 내가 이미 로이텀을 산 뒤라서 놓쳤다. 다음에는 한번 편하게 쓰는 노트로 펜코랑 얘를 같이 써볼까 고민중! 근데 로고가 .. 로고가 마음에 안들어 약간 오리같은.. 그 로고가
  • 무인양품 상질지 쓰는 노트들 (더블링, 문고본 노트, 1일1페이지 등) -> 내년 다이어리는 얘네로 당첨이다... 옥스포드 상철 노트나 무인양품 더블링노트를 스프링노트 대용으로 쓰면 좋을듯?!)

 

5. 사실 코테 볼 때 최고는... A4 용지다....

A4 용지에 클립홀더면 최고로 든든하고 가성비도 최고다^^ 

 

 

그 외에도 꽤 많이 써봤던 것 같은데 기억이 잘 안 남는다 무난하게 구하기 쉽고 가격대도 준수했던 노트들은 이정도인듯. 솔직히... 못생긴 표지의 노트는 도저히 못 쓰겠다. 차라리 깔끔한 단색으로 내줘.. 제발... 사실 먼슬리는 매번 다른 제품 샀다가 결국 로이텀으로 돌아오는 걸로 보아 로이텀 먼슬리를 사서 메인으로 쓰고, 나머지 노트들을 사이드로 들고 다니는게 무난한 것 같다 ㅎㅎ 내년의 나야 이상한데에 돈쓰지 말고,,, 이 글을 다시 참고해서 잘 구매하자!

 

그나저나 트위스비 에코 EF닙도 들이고 싶어서 아주 드릉드릉하다. 피스톤 필러 방식도 편해보이고 무엇보다 잉크 3ml나 들어가는 게 아주 매력적이다... 지금 있는 만년필들도 매일 못 써줘서 닙마름이 있는 상태라 일단 참는다 흑흑

 

 

물론... 이 노트들은 뭐 필사를 한다거나, 테가 뜬다거나 이런건 고려하지 않은 부분이다. 나도 테 뜨는 거 다 생각하면 겁나 좋고 비싼 노트나 아예 A4용지로 셀프 노트를 만들어 썼을 것 같다 ㅋㅋㅋ 그치만 테 뜨는 예쁜 잉크들을 어떻게 생각 정리하는 그런 우다다 필기에 쓰는가 아까워서... 글입다 공방 잉크는 그렇게 서랍에 고이 보관되어있다 ㅋㅋ 매번 쓰는건 라미 검정 잉크, 파카 잉크, 이런 무난한 제품뿐이다... ㅎ

 

 

에휴 미래의 나를 위해 또 다시 적는다.

트노 눈독들이지 말자 ㅋㅋ 그 종이 어차피... 중국수입산 종이나 32장에 5~6천원 주고 사야하는 스테이플러 방식이니까 그냥 로이텀 2023 먼슬리 + 무인양품 기타 노트 조합으로 쓰자 ㅇㅇㅇㅇ

 

아니면 미도리 하루한페이지 사서 쓰는것도 나쁘지 않아보이긴 한다 가계부까지 먼슬리에 적을 생각하면... L사이즈를 사야 하려나.... 쩝 근데 L는 거의 전공책 두께던데 ㅋㅋㅋㅋ 고민이다

npm stop같은 멋진 기능은 안 만들어둔 과거의 나...

sudo lsof -nPi -sTCP:LISTEN

기능 실행해서 몇번 pid에서 돌고 있나 보고 kill해주자

7213번에서 돌고있다 ㅡㅡ

kill -9 7213

 

해주고 다시 npm start 해주니까 잘 돌아간다~

+ Recent posts