✅ 20 회차 모의고사 D-11일

🚨 강의영상링크


🚀 1차 코딩테스트 대비

  1. 백준 14719 (빗물)
  2. 백준 1747 (소수&팰린드롬)
  3. 백준 1972 (놀라운 문자열)
  4. 백준 16120 (PPAP)
  5. SQL 진료과별 예약 횟수 출력하기

👨‍🏫 COLAB

1차 풀이

⭐ 1. 백준 14719 (빗물)

# 1. 알고(구현): 백준 14719 (빗물) - https://www.acmicpc.net/problem/14719
import sys
 
from io import StringIO
sys.stdin = StringIO('''4 8
3 1 2 3 4 1 1 2''')
 
input = sys.stdin.readline
 
def solve():
    H, W = map(int, input().split())
    heights = list(map(int, input().split()))
 
    left, right = 0, W - 1
 
    left_max = heights[left]
    right_max = heights[right]
 
    water = 0
    while left < right:
 
        if left_max < right_max:
            left += 1
            left_max = max(left_max, heights[left])
            water += left_max - heights[left]
 
        else:
            right -= 1
            right_max = max(right_max, heights[right])
            water += right_max - heights[right]
 
    print(water)
 
solve()

⭐ 2. 백준 1747 (소수&팰린드롬)

# 2. 알고(수학): 백준 1747 (소수&팰린드롬) - https://www.acmicpc.net/problem/1747
import sys
from math import isqrt
 
from io import StringIO
sys.stdin = StringIO('''31''')
 
input = sys.stdin.readline
 
def solve():
    N = int(input())
 
    def is_pelin(num):
        str_num = str(num)
        return str_num == str_num[::-1]
 
    def is_prime(num):
        if num == 1:
            return False
 
        for denom in range(2, isqrt(num) + 1):
            if num % denom == 0:
                return False
        return True
 
    number = N
    while True:
        if is_pelin(number) and is_prime(number):
            print(number)
            break
        number += 1
 
solve()

⭐ 3. 백준 1972 (놀라운 문자열)

# 3. 알고(Map): 백준 1972 (놀라운 문자열) - https://www.acmicpc.net/problem/1972
import sys
 
from io import StringIO
sys.stdin = StringIO('''ZGBG
X
EE
AAB
AABA
AABB
BCBABCC
*''')
 
input = sys.stdin.readline
 
def solve():
 
    def d_find(str_len):
 
        for length in range(2, str_len + 1):
            d_pair = set()
 
            for start in range(0, str_len - length + 1):
                end = start + length - 1
                temp = string[start] + string[end]
 
                if temp not in d_pair:
                    d_pair.add(temp)
                else:
                    return False
        
        return True
 
    while True:
        string = input().rstrip()
        if string == '*':
            break
        
        str_len = len(string)
 
        if d_find(str_len):
            print(f"{string} is surprising.")
        else:
            print(f"{string} is NOT surprising.")
 
solve()

⭐ 4. 백준 16120 (PPAP)

# 4. 알고(그리디): 백준 16120 (PPAP) - https://www.acmicpc.net/problem/16120
import sys
 
from io import StringIO
sys.stdin = StringIO('''PPPAPAP''')
 
input = sys.stdin.readline
 
def solve():
    ppap = list(input().rstrip())
    stack = []
 
    for char in ppap:
        stack.append(char)
        
        if len(stack) >= 4 and stack[-4:] == ['P', 'P', 'A', 'P']:
            del stack[-3:]
 
    print('PPAP') if stack == ['P'] else print('NP')
 
solve()

✏️ 5. SQL 진료과별 예약 횟수 출력하기

-- 5. SQL(Lv.2): 진료과별 예약 횟수 출력하기 
-- https://school.programmers.co.kr/learn/courses/30/lessons/132202
SELECT 
    MCDP_CD AS 진료과코드,
    COUNT(*) AS `5월예약건수` -- 백틱
FROM 
    APPOINTMENT 
WHERE
    APNT_YMD LIKE '2022-05%'
GROUP BY
    MCDP_CD
ORDER BY
    `5월예약건수` ASC,
    진료과코드 ASC;

🚀 2차 코딩테스트 대비

  1. 백준 17837 (새로운 게임 2)
  2. 백준 1937 (욕심쟁이 판다)
  3. 백준 13913 (숨바꼭질 4)
  4. 백준 12100 (2048 (Easy))
  5. SQL 상품을 구매한 회원 비율 구하기

👨‍🏫 COLAB

2차 풀이

⭐ 1. 백준 17837 (새로운 게임 2)

# 1. 알고(시뮬): 백준 17837 (새로운 게임 2) - https://www.acmicpc.net/problem/17837
# https://www.youtube.com/@sejongclass (코드 짠 사람)
import sys
 
from io import StringIO
sys.stdin = StringIO('''6 10
0 1 2 0 1 1
1 2 0 1 1 0
2 1 0 1 1 0
1 0 1 1 0 2
2 0 1 2 0 1
0 2 1 0 2 1
1 1 1
2 2 2
3 3 4
4 4 1
5 5 3
6 6 2
1 6 3
6 1 2
2 4 3
4 2 1''')
 
input = sys.stdin.readline
 
def solve():
    N, K = map(int, input().split())
    board = [list(map(int, input().split())) for _ in range(N)]
 
    directions = [(0, +1), (0, -1), (-1, 0), (+1, 0)]  # 우(0), 좌(1), 상(2), 하(3)
    rev_dir = [1, 0, 3, 2]      # 반대 방향
 
    horses = list()
    states = [[[] for _ in range(N)] for _ in range(N)]  # 각 좌표마다 스텍
 
    for i in range(K):
        r, c, dir = map(lambda x: int(x) - 1, input().split())  # 0 인덱스
        horses.append([r, c, dir])
        states[r][c].append(i)      # 말 배치
 
    for turn in range(1, 1001):
        for cur_i in range(K):
            r, c, dir = horses[cur_i]
 
            dr, dc = directions[dir]
            nr, nc = r + dr, c + dc
            in_range = 0 <= nr < N and 0 <= nc < N
 
            if not in_range or board[nr][nc] == 2:  # 벗어나거나, 파란색(2)인 경우
 
                dir = rev_dir[dir]      # 방향 전환
                horses[cur_i][2] = dir
 
                dr, dc = directions[dir]
                nr, nc = r + dr, c + dc
                in_range = 0 <= nr < N and 0 <= nc < N
 
                if not in_range or board[nr][nc] == 2:   # 또 벽, 파란색인 경우 다음 말.
                    continue
 
            # 이동 확정.
            cur_state = states[r][c]
            nxt_state = states[nr][nc]
 
            idx = cur_state.index(cur_i)        # 해당 말의 위치
            moving_group = cur_state[idx:]      # 이동할 말 복사.
            del cur_state[idx:]                 # 이전 말 제거
 
            for move_i in moving_group:         # 말 이동.
                horses[move_i][:2] = nr, nc
 
            if board[nr][nc] == 1:          # 빨강이면 말 순서 뒤집기
                moving_group.reverse()
 
            nxt_state.extend(moving_group)  # 다음칸에 말 쌓기.
 
            if len(nxt_state) >= 4:
                return print(turn)          # 4개 이상 쌓이면 종료.
 
    print(-1)
 
solve()

⭐ 2. 백준 1937 (욕심쟁이 판다)

# 2. 알고(DP): 백준 1937 (욕심쟁이 판다) - https://www.acmicpc.net/problem/1937
import sys
from itertools import product
 
from io import StringIO
sys.stdin = StringIO('''4
14 9 12 10
1 11 5 4
7 15 2 13
6 3 16 8''')
 
input = sys.stdin.readline
 
def solve():
    N = int(input())
    board = [tuple(map(int, input().split())) for _ in range(N)]
    directions = [(0, +1), (0, -1), (+1, 0), (-1, 0)]
 
    starts = sorted(  # 작은 수의 대나무 부터 조사.
        (board[r][c], r, c)
        for r, c in product(range(N), repeat=2)
    )
 
    # dp[r][c] = 이 위치에 도달 할 수 있는 최대 길이
    dp = [[0] * N for _ in range(N)]
    answer = 0
 
    for cur_bamboo, r, c in starts:
        max_len = 0
 
        for dr, dc in directions:
            pr, pc = r + dr, c + dc
            if not 0 <= pr < N or not 0 <= pc < N:
                continue
 
            # 현재 위치로 올 수 있는 이전 방향 거리들 조사
            if cur_bamboo > board[pr][pc]:
                max_len = max(max_len, dp[pr][pc])
 
        dp[r][c] = max_len + 1  # 자신의 값 추가.
        answer = max(answer, max_len + 1)
 
    print(answer)
 
solve()

⭐ 3. 백준 13913 (숨바꼭질 4)

# 3. 알고(그래프): 백준 13913 (숨바꼭질 4) - https://www.acmicpc.net/problem/13913
import sys
from collections import deque
 
from io import StringIO
sys.stdin = StringIO('''5 17''')
 
input = sys.stdin.readline
 
def solve():
    N, K = map(int, input().split())
    MAX = 100_000
 
    prev = [-1] * (MAX + 1)   # 방문 기능 함께 통합
 
    dq = deque([N])
    prev[N] = N
 
    while dq:
        cur = dq.popleft()
        if cur == K:
            break
 
        for nxt in (cur + 1, cur - 1, cur*2):
            if not 0 <= nxt <= MAX or prev[nxt] != -1:
                continue
 
            dq.append(nxt)
            prev[nxt] = cur
 
    posi = K
    answer = []
 
    while posi != N:
        answer.append(posi)
        posi = prev[posi]
 
    answer.append(N)
    answer.reverse()
 
    print(len(answer) - 1)
    print(*answer)
 
solve()

⭐ 4. 백준 12100 (2048 (Easy))

# 4. 알고(백트래킹): 백준 12100 (2048 (Easy)) - https://www.acmicpc.net/problem/12100
import sys
 
from io import StringIO
sys.stdin = StringIO('''3
2 2 2
4 4 4
8 8 8''')
 
input = sys.stdin.readline
 
def solve():
    N = int(input())
    board = [list(map(int, input().split())) for _ in range(N)]
    max_val = max(map(max, board))
 
    def compress_merge(one_line):
        nonlocal max_val
 
        arr = [x for x in one_line if x != 0]  # 0 제거 후 복사
        merged = list()
        base_idx = 0
 
        while base_idx < len(arr):
            base = arr[base_idx]
            target = base_idx + 1
 
            if target < len(arr) and base == arr[target]:
                max_val = max(max_val, base * 2)
                merged.append(base * 2)
                base_idx += 2
            else:
                merged.append(arr[base_idx])
                base_idx += 1
 
        merged.extend([0] * (N - len(merged)))
        return merged
 
    def can_move(dir):
        is_moved = False            # 이동이 일어났는지 체크
 
        if dir == 0 or dir == 1:    # dir, 0좌, 1우, 2위, 3아래
            for r in range(N):      # 우측이면 반전
 
                line = board[r][::-1] if dir == 1 else board[r]
                new_line = compress_merge(line)
                if not is_moved:    # 이동 여부
                    is_moved = line != new_line
 
                if dir == 1:
                    new_line.reverse()
                board[r][:] = new_line
 
        else:
            for c in range(N):      # 아래면 반전
                line = [board[r][c] for r in range(N)]
                if dir == 3:
                    line.reverse()
 
                new_line = compress_merge(line)
                if not is_moved:
                    is_moved = line != new_line
                if dir == 3:
                    new_line.reverse()
                for r in range(N):
                    board[r][c] = new_line[r]
 
        return is_moved
 
    def dfs(trying_cnt):
 
        if trying_cnt > 5:
            return
 
        snapshot = [row[:] for row in board]    # 현재 상태 저장
        for dir in range(4):
            if can_move(dir):
                dfs(trying_cnt + 1)
            for r in range(N):                  # 보드 복원
                board[r][:] = snapshot[r]
 
    dfs(1)
    print(max_val)
 
solve()

✏️ 5. SQL 상품을 구매한 회원 비율 구하기

-- 5. SQL(Lv.5): 상품을 구매한 회원 비율 구하기 
-- https://school.programmers.co.kr/learn/courses/30/lessons/131534
WITH 
    JOIN_21 AS (
        SELECT
            USER_ID,
            COUNT(*) OVER() AS TOTAL_USERS
        FROM 
            USER_INFO 
        WHERE
            YEAR(JOINED) = 2021
    )
SELECT
    YEAR(SALES_DATE) AS `YEAR`,
    MONTH(SALES_DATE) AS `MONTH`,
    COUNT(DISTINCT USER_ID) AS `PURCHASED_USERS`,
    ROUND(
        COUNT(DISTINCT USER_ID) / TOTAL_USERS, 
        1
    ) AS `PUCHASED_RATIO`
FROM JOIN_21
JOIN ONLINE_SALE USING(USER_ID)
GROUP BY
    YEAR, MONTH
ORDER BY
    YEAR ASC, MONTH ASC;