63일차

Suhyeon Lee·2024년 12월 30일

CodeKata

SQL

프로그래머스: 잡은 물고기 중 가장 큰 물고기의 길이 구하기

  • 작성한 쿼리
SELECT
  CONCAT(MAX(length), 'cm') AS max_length
FROM
  fish_info
;

참고할 만한 다른 풀이

SELECT  CONCAT(A.MAX_LENGTH, 'cm') AS MAX_LENGTH
  FROM  (
               SELECT  FI.LENGTH AS MAX_LENGTH
                 FROM  FISH_INFO FI
             ORDER BY  FI.LENGTH DESC
                LIMIT  1
        ) A
SELECT DISTINCT(CONCAT(LENGTH,'cm')) AS MAX_LENGTH
FROM FISH_INFO
WHERE LENGTH IN (SELECT MAX(LENGTH)
                FROM FISH_INFO)

프로그래머스: 연도별 대장균 크기의 편차 구하기

  • 작성한 쿼리
SELECT
  YEAR(DIFFERENTIATION_DATE) AS `YEAR`
  , MAX(SIZE_OF_COLONY) OVER (PARTITION BY YEAR(DIFFERENTIATION_DATE)) - SIZE_OF_COLONY AS YEAR_DEV
  , ID
FROM
  ECOLI_DATA
ORDER BY
  `YEAR`
  , YEAR_DEV
;

참고할 만한 다른 풀이

SELECT 
YEAR(A.DIFFERENTIATION_DATE) YEAR,
(C.MAX_C - A.SIZE_OF_COLONY) YEAR_DEV,
A.ID
FROM 
ECOLI_DATA A 
JOIN
(
 SELECT MAX(SIZE_OF_COLONY) MAX_C, YEAR(DIFFERENTIATION_DATE) DATE
 FROM ECOLI_DATA 
 GROUP BY DATE
) C
ON YEAR(A.DIFFERENTIATION_DATE) = C.DATE
ORDER BY 
YEAR(A.DIFFERENTIATION_DATE) ASC, 
YEAR_DEV ASC
-- 1
WITH MAX_SIZE AS
(SELECT YEAR(DIFFERENTIATION_DATE) YEAR, MAX(SIZE_OF_COLONY) MAX_SIZE
FROM ECOLI_DATA
GROUP BY 1)
SELECT M.YEAR, (MAX_SIZE - E.SIZE_OF_COLONY) YEAR_DEV, ID
FROM ECOLI_DATA E
LEFT JOIN MAX_SIZE M ON YEAR(E.DIFFERENTIATION_DATE) = M.YEAR
ORDER BY 1, 2

--2
SELECT YEAR(DIFFERENTIATION_DATE) YEAR, 
    (SELECT MAX(SIZE_OF_COLONY) FROM ECOLI_DATA WHERE YEAR(DIFFERENTIATION_DATE) = YEAR) - SIZE_OF_COLONY as YEAR_DEV,
    ID
FROM ECOLI_DATA 
ORDER BY YEAR, YEAR_DEV

※ with를 써서 조인하는 경우 최댓값을 한번만 계산하고 그 값을 조인하는데
서브쿼리로 넣으면 각 행마다 최댓값을 계산함

Python

72. 달리기 경주

  • 작성한 코드
def solution(players, callings):
    answer = []
    
    players_dict = {}
    rank_dict = {}
    
    for idx, i in enumerate(players):
        players_dict[i] = idx
        rank_dict[idx] = i

    for i in callings:
        rank_now = players_dict[i]
        players_dict[i] = rank_now - 1
        players_dict[rank_dict[rank_now-1]] = rank_now
        rank_dict[rank_now] = rank_dict[rank_now - 1]
        rank_dict[rank_now - 1] = i
    answer= list(rank_dict.values())
    return answer

QnA

  • 왜 아래와 같이 풀면 안 되나?
def solution(players, callings):
    for x in callings:
        rank = players.index(x)
        players[rank], players[rank-1] = players[rank-1], players[rank]
    return players

일반적으로 O(n)에서 n의 값이 1억을 넘으면 통과가 어렵다고 보면 되는데 2줄과 3줄이 독립적으로 callings 배열(크기:M)과 players 배열(크기:N)의 크기에 비례하기 때문에 시간복잡도는 둘의 곱인 O(MN)이 되어 이 방법으로 풀 수 없습니다. 일반적으로 O(n)에서 n의 값이 1억을 넘으면 통과가 어렵다고 보면 되는데, 문제 조건을 보면 백만*5만=5백억이라는 수가 나오죠. 이 문제는 양방향 인덱싱을 이용해야 하고, 그러기 위해선 딕셔너리 두 개 또는 딕셔너리 하나와 리스트 하나가 필요합니다.

→ 인덱스는 모든 리스트에 대해서 하나씩 순차적으로 검사를 해서 시간이 많이 걸린다고 하네요. 하지만 딕셔너리로 바꾸게 되면 hash값을 가진 트리구조로 Key값을 저장하기 때문에 index에 비해서 찾아내는 속도가 월등히 빠르다고 합니다.

→ index의 시간복잡도가 O(n)인데, 이걸 callings에 대한 for문 안에 넣으면 시간복잡도가 O(n^2) 라서 시간초과가 발생합니다.

  • 딕셔너리를 한 개 쓰는 것과 두 개 쓰는 것의 차이
    • 매번 추월한 선수가 호명될 때마다 swap하지 않고, 등수:선수에도 동시에 반영하면 최종 결과를 리턴할 때 더 빠른 시간에 실행이 가능
def solution(players, callings):
    result = {player: i for i, player in enumerate(players)} # 선수: 등수
    for who in callings:
        idx = result[who] # 호명된 선수의 현재 등수
        result[who] -= 1 # 하나 앞 등수로 바꿔줌 -1
        result[players[idx-1]] += 1 # 앞에 위치했던 선수의 등수 +1
        players[idx-1], players[idx] = players[idx], players[idx-1] # 위치 변경
    return players
  1. callings에 담긴 선수들의 이름을 하나씩 가져온다.
  2. 해당 선수가 현재 몇 등인지 result에서 찾아 idx에 저장한다.
  3. 그런 다음, 방금 호명된 선수는 바로 앞사람을 추월한 것이므로 -1를 하여 하나 앞 등수로 바꿔준다.
  4. 그럼 추월당한 선수는 하나 뒷 등수로 바꿔주어야 한다. 이 선수는 players에서 idx-1에 위치했던 선수이고, 등수 반영을 위해 result에서 이 선수에 해당하는 등수를 +1 해준다.
  5. 마지막으로 두 선수의 바뀐 위치를 swap을 이용하여 players에 반영해 준다.

참고할 만한 풀이

def solution(players, callings):
    answer = []

    p_dic = {player:i+1 for i,player in enumerate(players)}
    location_dic = {i+1:player for i,player in enumerate(players)}

    for c in callings:
        c_loc = p_dic[c]
        front = c_loc - 1
        front_p = location_dic[front]
        p_dic[c] -= 1
        p_dic[front_p] += 1
        location_dic[c_loc] = front_p
        location_dic[front] = c



    p_dic = dict(sorted(p_dic.items(),key=lambda x:x[1]))
    answer = list(p_dic.keys())

    return answer
def solution(players, callings):
    # 선수에 대한 딕셔너리 만들기
    player_rank = {}
    rank_player = {}
    for i in range(len(players)):
        player_rank[players[i]] = i+1
        rank_player[i+1] = players[i]

    for call in callings:
        num = player_rank[call]
        front_p = rank_player[num-1]

        #swap
        rank_player[num-1], rank_player[num] = rank_player[num], rank_player[num-1]
        player_rank[front_p], player_rank[call] = player_rank[call], player_rank[front_p]

        #rank_player 업데이트
    return list(rank_player.values())
def solution(players, callings):
    answer = []
    player_dict = dict()

    for i, player in enumerate(players):
        player_dict[player] = i

    swap = ""
    swap_int = 0
    player_1 = ""
    player_2 = ""

    for call in callings:
        index = player_dict[call]
        player_1 = players[index-1]
        player_2 = players[index]
        #print(index)

        swap = players[index]
        players[index] = players[index-1]
        players[index-1] = swap

        player_dict[player_1] = index
        player_dict[player_2] = index - 1

    return players

Spark를 이용한 빅데이터 분석

1주차

Latte Talk

  • 이커머스 구매 퍼널 관련
    • 결제, 환불 과정을 쉽게 만드는 과정에서 환불 비율 증가가 많아지지 않았나요?
      → 처음 적용하고 나서 일부 환불 비율이 증가했는데 이후 나아졌습니다! 환불도 가드레일 중 하나에요. 가드레일이 실제로 안좋아지면 2-3주 더 실험을 돌리기도 해요! (novelty effect 라는게 존재해서)
    • 프로덕트 분석가가 직접 소프트웨어 개발도 하기도 하시나요?
      → 아니요 개발은 개발자쪽에서 해요!

최종 프로젝트 고민

방송 알리미 만들기
덥덥미
게임 데이터 스크래핑 전략
스팀 게임과 리뷰 크롤링
steam 관련
게임 리뷰 평가 예측 API
Steam Game Recomend Model
유튜브(Youtube) API
유튜브 데이터 API 뜯어보기
Youtube API 가지고 놀기
유튜브 영상 데이터 리스트업

pokemon tcg mobile
이터널 리턴 승률 검색 개발자

op.gg
pokemon tcg pocket

겜린더

회고

  • 비슷한 취향의 분들과 최종 프로젝트를 함께 하게 되었다!
    • 하고 싶은 건 많은데 이걸 실제로 구현할 수 있을지 모르겠어서 확실하게 주제를 정하진 못함…
profile
2 B R 0 2 B

0개의 댓글