TODAY TIL

오늘의 문제는  프로그래머스에 있는 크기가 작은 부분 문자열 였는데요.

아직 알고리즘이 익숙하지 않은 초보지만 푼 내용을 정리하기 위해서 작성해 봅니다.

 

문제 설명
주어진 숫자 문자열 t와 p가 있을 때, t에서 p와 길이가 같은 부분 문자열을 잘라내어 숫자로 변환한 뒤, 이 숫자가 p보다 작거나 같은 경우를 찾는 문제입니다.

  • 예를 들어, t = "3141592"이고 p = "271"이라면, t에서 길이가 3인 부분 문자열을 추출하여 숫자로 변환하고 271보다 작거나 같은 경우를 세어야 합니다.

입력 예시

  • t = "3141592"
  • p = "271"

출력 예시

  • 결과: 2 (141, 159 두 개의 숫자가 271보다 작음)

문제 해결 방법

이 문제를 단계별로 쉽게 풀이해보겠습니다.

  1. 부분 문자열 길이 구하기
    p의 길이와 같은 길이의 부분 문자열을 t에서 잘라낼 것입니다. 따라서, p의 길이를 미리 구해 놓습니다.
  2. 반복문으로 부분 문자열 만들기
    t에서 p의 길이만큼 부분 문자열을 하나씩 잘라내야 하므로, t를 처음부터 끝까지 순회하면서 p와 같은 길이의 부분 문자열을 만듭니다.
  3. 숫자 변환 후 비교하기
    잘라낸 부분 문자열을 숫자로 변환한 뒤, p와 비교합니다. 만약 p보다 작거나 같은 숫자라면, 이 부분 문자열은 조건에 맞는 것이 됩니다.
  4. 개수 세기
    조건에 맞는 부분 문자열이 나올 때마다 개수를 하나씩 더합니다.
  5. 최종 결과 반환하기
    반복이 끝나면 조건에 맞는 부분 문자열의 개수를 반환합니다.

코드 구현

def solution(t, p):
    length_p = len(p)  # p의 길이를 구해서 저장
    count = 0  # 조건에 맞는 부분 문자열 개수를 세기 위한 변수
    
    for i in range(len(t) - length_p + 1):  # t에서 부분 문자열을 잘라내기 위한 반복문
        substring = t[i:i + length_p]  # 부분 문자열 생성
        if int(substring) <= int(p):  # 숫자로 변환해 p와 비교
            count += 1  # 조건을 만족하면 count를 1 증가
    
    return count  # 최종 개수 반환

 

 

한 줄씩 아주 쉽게 설명하기

  1. length_p = len(p)
    • p의 길이를 구해서 length_p에 저장. 이 길이만큼 t에서 잘라냄
  2. count = 0
    • 조건에 맞는 숫자가 몇 개인지 세기 위해 처음에 count를 0으로 설정.
  3. for i in range(len(t) - length_p + 1)
    • t에서 p와 같은 길이만큼 잘라낼 건데, 한 글자씩 오른쪽으로 이동하면서 잘라냄.
    • 예를 들어, p의 길이가 3이면 t에서 첫 글자부터 3글자씩 이동하면서 반복.
  4. substring = t[i:i + length_p]
    • t의 i 위치부터 p와 같은 길이만큼 잘라내서 substring이라는 부분 문자열을 만듬.
    • 예를 들어, t = "3141592"이고 p = "271"이라면, substring이 314, 141, 415... 이렇게 돼요.
  5. if int(substring) <= int(p)
    • substring과 p를 숫자로 바꿔서 비교
    • 만약 substring이 p보다 작거나 같으면 조건을 만족
  6. count += 1
    • 조건을 만족하면 count를 1씩 더해요.
  7. return count
    • 마지막으로 조건에 맞는 개수(count)를 결과로 내보내요.

코드 예시

출력 결과

  • 예를 들어, t = "3141592"이고 p = "271"이면:
    • 314, 141, 415, 159, 592 중에서 271보다 작거나 같은 숫자는 141과 159 두 개니까, 답은 2가 됩니다.

✍️ 풀이 요약

이 문제는 주어진 문자열에서 특정 조건을 만족하는 부분 문자열을 찾아서 개수를 세는 문제입니다. p의 길이만큼 부분 문자열을 t에서 하나씩 잘라내면서, p보다 작거나 같은지를 비교하는 방식으로 간단하게 풀이할 수 있습니다.

 

문제 풀고 느낀점

  • 어떻게 풀어야 할지 생각을 많이 해서 풀게되었다.
  • 문제를 해석하고 하나하나씩 풀어나가는게 중요하다는걸 느꼈다.
  • CHAT GPT를 사용한다면 바로 답을 알려달라고 하지말고 문제 푸는 방법에 대해서 물어보자 그럼 해결방법의 힌트를 제공해준다.
  • 코드를 모르면 하나씩 설명해 달라고 하자 이해하기가 쉽다.
 

 

오늘의 공부 키워드

2864  Maximim odd Binary Number

 

2864  Maximim odd Binary Number

문제 설명

이진 문자열 s가 주어졌을 때, 이 문자열을 재배열하여 만들 수 있는 가장 큰 홀수 이진 숫자를 구하는 것입니다. 홀수 이진 숫자는 마지막 자리가 '1'이어야 합니다. 주어진 문자열에는 최소한 하나의 '1'이 포함되어 있습니다.

 

예제

  1. 입력: s = "010"
    • 출력: "001"
    • 설명: '1'이 하나밖에 없으므로 마지막 자리에 위치시킵니다. 따라서 답은 "001"입니다.
  2. 입력: s = "0101"
    • 출력: "1001"
    • 설명: '1' 중 하나는 마지막에 배치하고, 나머지 숫자들을 앞에 배치하여 가장 큰 숫자를 만듭니다. 따라서 답은 "1001"입니다.

문제 해결 방법

이 문제를 해결하기 위한 단계는 다음과 같습니다:

  1. 주어진 문자열 s에서 '1'의 개수를 셉니다.
  2. 마지막 자리에 '1'을 하나 배치합니다.
  3. 나머지 '1'과 '0'을 모두 앞에 배치하여 가장 큰 숫자를 만듭니다

 

파이썬 코드 구현

def maximumOddBinaryNumber(s: str) -> str:
    count_1 = s.count('1')
    count_0 = len(s) - count_1
    
    # '1' 하나는 마지막에 배치
    result = '1' * (count_1 - 1) + '0' * count_0 + '1'
    return result

# 예제 입력을 테스트해보세요.
print(maximumOddBinaryNumber("010"))  # 출력: "001"
print(maximumOddBinaryNumber("0101")) # 출력: "1001"

 

코드 설명

  1. count_1 = s.count('1')는 문자열 s에서 '1'의 개수를 셉니다.
  2. count_0 = len(s) - count_1는 문자열 s에서 '0'의 개수를 셉니다.
  3. '1' * (count_1 - 1) + '0' * count_0 + '1'는 마지막 자리에 '1'을 배치하고, 나머지 '1'과 '0'을 앞에 배치하여 가장 큰 숫자를 만듭니다.

이와 같은 방법으로 주어진 이진 문자열을 재배열하여 가장 큰 홀수 이진 숫자를 만들 수 있습니다. 이 문제는 간단하지만, 기본적인 이진수의 특성과 문자열 처리 방법을 이해하는 데 도움이 됩니다.

 

마무리

이 글에서는 이진 문자열을 재배열하여 최대 홀수 이진 숫자를 만드는 문제를 해결하는 방법을 설명했습니다. 파이썬 코드를 통해 문제 해결 과정을 자세히 설명하였으니, 비슷한 문제를 해결할 때 도움이 되길 바랍니다.

여러분도 직접 코드를 작성해 보고, 다양한 입력값으로 테스트해 보세요. 이를 통해 문제 해결 능력을 키울 수 있을 것입니다. 감사합니다!

 

오늘의 공부 키워드

1337 The K Weakest Rows in a Matrix

 

1337 The K Weakest Rows in a Matrix

이 문제는 이진 행렬에서 각 행의 군인 수를 계산하고, 주어진 k 값에 따라 가장 약한 행의 인덱스를 반환하는 문제입니다. 주어진 조건에 따라 각 행의 군인 수를 계산하고, 같은 수의 군인을 가진 행은 인덱스 순서대로 정렬합니다. 이를 통해 가장 약한 k개의 행을 구할 수 있습니다.

 

문제를 해결하는 방법은 다음과 같습니다:

  1. 각 행의 군인 수를 계산합니다.
  2. 행의 인덱스와 군인 수를 튜플로 묶어 리스트를 만듭니다.
  3. 이 리스트를 군인 수와 인덱스를 기준으로 정렬합니다.
  4. 정렬된 리스트에서 가장 약한 k개의 행의 인덱스를 추출합니다.

파이썬코드

def kWeakestRows(mat, k):
    # 각 행의 군인 수를 계산하여 리스트 생성
    soldiers_count = [(sum(row), index) for index, row in enumerate(mat)]
    
    # 군인 수와 인덱스를 기준으로 정렬
    soldiers_count.sort()
    
    # 가장 약한 k개의 행의 인덱스를 추출하여 반환
    return [index for _, index in soldiers_count[:k]]

# 예시 입력
mat1 = [
    [1, 1, 0, 0, 0],
    [1, 1, 1, 1, 0],
    [1, 0, 0, 0, 0],
    [1, 1, 0, 0, 0],
    [1, 1, 1, 1, 1]
]
k1 = 3

mat2 = [
    [1, 0, 0, 0],
    [1, 1, 1, 1],
    [1, 0, 0, 0],
    [1, 0, 0, 0]
]
k2 = 2

# 결과 출력
print(kWeakestRows(mat1, k1))  # Output: [2, 0, 3]
print(kWeakestRows(mat2, k2))  # Output: [0, 2]

 

이 코드는 각 행의 군인 수를 계산하고, 이를 이용해 행을 정렬한 후 가장 약한 k개의 행의 인덱스를 반환합니다. 행렬의 각 행은 튜플 형태로 군인 수와 인덱스를 가지고 정렬되며, 이를 통해 약한 행을 쉽게 찾을 수 있습니다.

 

 

오늘의 공부 키워드

2500 Delete Greatest Value in Each Row

 

2500 Delete Greatest Value in Each Row

 

 

이 문제에서 주어진 m x n 행렬 grid는 양의 정수로 이루어져 있습니다. 문제에서 요구하는 연산을 수행하여 grid가 빌 때까지 계속 진행해야 합니다.

주어진 연산은 다음과 같습니다:

  1. 각 행에서 가장 큰 값을 삭제합니다. 만약 가장 큰 값이 여러 개 있다면 그 중 하나를 임의로 삭제합니다.
  2. 삭제된 원소들 중 최대값을 결과값(answer)에 더합니다.

이 연산을 모든 열이 삭제될 때까지 반복하고, 최종적으로 answer 값을 반환합니다.

해석 예제 1:

입력: grid = [[1,2,4],[3,3,1]] 출력: 8 설명: 각 단계에서 삭제된 값을 보여줍니다.

  • 첫 번째 연산에서, 첫 번째 행에서 4를 삭제하고 두 번째 행에서 3을 삭제합니다(3이 두 개 있으며 하나를 임의로 삭제할 수 있습니다). 4를 결과에 추가합니다.
  • 두 번째 연산에서, 첫 번째 행에서 2를 삭제하고 두 번째 행에서 3을 삭제합니다. 3을 결과에 추가합니다.
  • 세 번째 연산에서, 첫 번째 행에서 1을 삭제하고 두 번째 행에서 1을 삭제합니다. 1을 결과에 추가합니다. 최종 결과 = 4 + 3 + 1 = 8.

해석 예제 2:

입력: grid = [[10]] 출력: 10 설명: 각 단계에서 삭제된 값을 보여줍니다.

  • 첫 번째 연산에서, 행에서 10을 삭제합니다. 10을 결과에 추가합니다. 최종 결과 = 10.

풀이 방법:

문제의 요구사항을 따르면 각 행에서 최대값을 찾고, 이 중에서 전체의 최대값을 뽑아 더하는 과정을 반복합니다. m이 행의 수, n이 열의 수이므로, 각 단계마다 O(m) 시간이 걸리며, 최대값을 찾는 것은 O(n)이므로 전체 연산은 O(m * n)의 시간 복잡도를 갖습니다. 각 열을 한 번씩 삭제하므로 총 O(n * m * n)의 연산이 필요합니다. 그러나 이는 최악의 경우이며, 일반적인 파이썬의 내장 함수를 사용하여 최적화할 수 있습니다.

 

파이썬 코드

def max_value_removals(grid):
    answer = 0
    while grid[0]:  # 이 반복은 최대 n번 (열의 수 만큼)
        max_vals = []
        for row in grid:
            max_val = max(row)
            max_vals.append(max_val)
            row.remove(max_val)  # 가장 큰 값 하나를 삭제
        answer += max(max_vals)  # 각 행에서 삭제된 값 중 최대값을 더함
    return answer

# 예제 실행
print(max_value_removals([[1,2,4],[3,3,1]]))  # 출력: 8
print(max_value_removals([[10]]))  # 출력: 10

 

오늘의 공부 키워드

682 Baseball Game

 

682 Baseball Game

문제 설명

야구 게임이 시작될 때 기록은 비어 있습니다. 주어진 명령어 리스트를 순서대로 처리하며 점수를 기록합니다. 명령어는 다음과 같습니다:

  • 정수 x: 새로운 점수 x를 기록합니다.
  • '+': 이전 두 점수의 합을 새로운 점수로 기록합니다.
  • 'D': 이전 점수의 두 배를 새로운 점수로 기록합니다.
  • 'C': 이전 점수를 무효화하고 기록에서 제거합니다.

모든 명령어를 처리한 후 기록된 모든 점수의 합을 반환합니다.

예시

예시 1

입력: ops = ["5", "2", "C", "D", "+"] 출력: 30

설명:

  • "5" -> 기록에 5를 추가, 기록: [5]
  • "2" -> 기록에 2를 추가, 기록: [5, 2]
  • "C" -> 마지막 점수 2를 제거, 기록: [5]
  • "D" -> 마지막 점수 5의 두 배인 10을 추가, 기록: [5, 10]
  • "+" -> 마지막 두 점수 5와 10의 합인 15를 추가, 기록: [5, 10, 15]

기록된 점수의 합: 5 + 10 + 15 = 30

예시 2

입력: ops = ["5", "-2", "4", "C", "D", "9", "+", "+"] 출력: 27

설명:

  • "5" -> 기록에 5를 추가, 기록: [5]
  • "-2" -> 기록에 -2를 추가, 기록: [5, -2]
  • "4" -> 기록에 4를 추가, 기록: [5, -2, 4]
  • "C" -> 마지막 점수 4를 제거, 기록: [5, -2]
  • "D" -> 마지막 점수 -2의 두 배인 -4를 추가, 기록: [5, -2, -4]
  • "9" -> 기록에 9를 추가, 기록: [5, -2, -4, 9]
  • "+" -> 마지막 두 점수 -4와 9의 합인 5를 추가, 기록: [5, -2, -4, 9, 5]
  • "+" -> 마지막 두 점수 9와 5의 합인 14를 추가, 기록: [5, -2, -4, 9, 5, 14]

기록된 점수의 합: 5 + (-2) + (-4) + 9 + 5 + 14 = 27

예시 3

입력: ops = ["1", "C"] 출력: 0

설명:

  • "1" -> 기록에 1을 추가, 기록: [1]
  • "C" -> 마지막 점수 1을 제거, 기록: []

기록된 점수의 합: 0

 

해결 방법

  1. 기록을 저장할 빈 리스트를 생성합니다.
  2. 주어진 명령어 리스트를 순차적으로 처리합니다.
  3. 각 명령어에 따라 기록을 업데이트합니다.
  4. 모든 명령어를 처리한 후 기록된 점수의 합을 반환합니다.

 

파이썬 코드

from typing import List

class Solution:
    def calPoints(self, operations: List[str]) -> int:
        record = []
        
        for op in operations:
            if op == "C":
                record.pop()
            elif op == "D":
                record.append(2 * record[-1])
            elif op == "+":
                record.append(record[-1] + record[-2])
            else:
                record.append(int(op))
        
        return sum(record)

# 예시 실행
solution = Solution()

ops1 = ["5", "2", "C", "D", "+"]
print(solution.calPoints(ops1))  # 출력: 30

ops2 = ["5", "-2", "4", "C", "D", "9", "+", "+"]
print(solution.calPoints(ops2))  # 출력: 27

ops3 = ["1", "C"]
print(solution.calPoints(ops3))  # 출력: 0

 

이 코드는 주어진 명령어 리스트를 순차적으로 처리하며 기록을 관리하고, 최종적으로 기록된 점수의 합을 계산하여 반환합니다. 예시 입력값에 대해 메서드를 호출하여 올바른 출력이 나오는지 확인할 수 있습니다.

 

오늘의 공부 키워드

1475 Final Prices With a Special Discount in a Shop

 

1475 Final Prices With a Special Discount in a Shop

문제 설명

주어진 정수 배열 prices에서 각 아이템의 가격이 주어집니다. 특별 할인을 받을 수 있는 조건은 다음과 같습니다:

  • i번째 아이템을 살 때, j가 i보다 크고 prices[j]가 prices[i]보다 작거나 같은 최소의 인덱스를 찾아서 prices[j] 만큼의 할인을 받습니다.
  • 만약 그런 인덱스가 없다면 할인을 받지 못합니다.

주어진 배열 prices에서 각 아이템의 최종 지불 가격을 계산하여 반환하는 정수 배열 answer를 반환하는 문제입니다.

예제

  1. 예제 1:
    • 입력: prices = [8, 4, 6, 2, 3]
    • 출력: [4, 2, 4, 2, 3]
    • 설명:
      • 아이템 0: 가격은 8이고, 최소 인덱스 1에서 4만큼 할인받아 최종 가격은 4입니다.
      • 아이템 1: 가격은 4이고, 최소 인덱스 3에서 2만큼 할인받아 최종 가격은 2입니다.
      • 아이템 2: 가격은 6이고, 최소 인덱스 3에서 2만큼 할인받아 최종 가격은 4입니다.
      • 아이템 3: 할인을 받지 못하여 최종 가격은 2입니다.
      • 아이템 4: 할인을 받지 못하여 최종 가격은 3입니다.
  2. 예제 2:
    • 입력: prices = [1, 2, 3, 4, 5]
    • 출력: [1, 2, 3, 4, 5]
    • 설명: 모든 아이템이 할인을 받지 못합니다.
  3. 예제 3:
    • 입력: prices = [10, 1, 1, 6]
    • 출력: [9, 0, 1, 6]
    • 설명:
      • 아이템 0: 가격은 10이고, 최소 인덱스 1에서 1만큼 할인받아 최종 가격은 9입니다.
      • 아이템 1: 가격은 1이고, 최소 인덱스 2에서 1만큼 할인받아 최종 가격은 0입니다.
      • 아이템 2: 할인을 받지 못하여 최종 가격은 1입니다.
      • 아이템 3: 할인을 받지 못하여 최종 가격은 6입니다.

파이썬코드

def finalPrices(prices):
    n = len(prices)
    answer = [0] * n

    for i in range(n):
        discount = 0
        for j in range(i + 1, n):
            if prices[j] <= prices[i]:
                discount = prices[j]
                break
        answer[i] = prices[i] - discount

    return answer

# 예제 테스트
print(finalPrices([8, 4, 6, 2, 3]))  # 출력: [4, 2, 4, 2, 3]
print(finalPrices([1, 2, 3, 4, 5]))  # 출력: [1, 2, 3, 4, 5]
print(finalPrices([10, 1, 1, 6]))    # 출력: [9, 0, 1, 6]

 

풀이 방법

이 문제를 해결하기 위해 다음과 같은 단계로 접근할 수 있습니다:

  1. prices 배열을 순회하면서 각 아이템의 가격을 확인합니다.
  2. 각 아이템의 가격에 대해 뒤에 나오는 가격 중에서 최소 가격을 찾습니다.
  3. 최소 가격을 찾아서 할인을 적용하고 최종 가격을 계산합니다.
  4. 최종 가격을 answer 배열에 저장합니다.

결론

이 글에서는 파이썬을 사용하여 'Final Prices With a Special Discount in a Shop' 문제를 해결하는 방법에 대해 살펴보았습니다. 각 아이템에 대해 뒤에 나오는 최소 가격을 찾아 할인을 적용하는 방법을 사용하여 문제를 해결할 수 있었습니다. 이 문제를 통해 조건문과 반복문을 활용한 배열 탐색 방법을 익힐 수 있습니다.

 

오늘의 공부 키워드

1700. Number of Students Unable to Eat Lunch

 

 

1700. Number of Students Unable to Eat Lunch

문제 설명

학교 급식실에서는 점심시간에 원형과 사각형 샌드위치를 제공합니다. 각각 0과 1로 표현됩니다. 모든 학생들은 줄을 서서 각자 원형 또는 사각형 샌드위치를 선호합니다.

샌드위치의 수는 학생들의 수와 같습니다. 샌드위치는 스택에 쌓여 있습니다. 각 단계에서 다음이 이루어집니다:

  • 줄의 맨 앞 학생이 스택 맨 위의 샌드위치를 선호하면 샌드위치를 가져가고 줄에서 나갑니다.
  • 그렇지 않으면, 샌드위치를 두고 줄의 끝으로 갑니다.

이 과정은 더 이상 줄의 학생들이 스택 맨 위의 샌드위치를 원하지 않아 먹지 못하는 상황이 될 때까지 계속됩니다.

두 개의 정수 배열 students와 sandwiches가 주어집니다. sandwiches[i]는 스택의 i번째 샌드위치의 타입(0이 맨 위)이고, students[j]는 줄의 j번째 학생의 선호도(0이 맨 앞)입니다. 먹지 못하는 학생의 수를 반환하세요.

 

예제

예제 1

  • 입력: students = [1,1,0,0], sandwiches = [0,1,0,1]
  • 출력: 0
  • 설명:
    1. 맨 앞 학생이 맨 위의 샌드위치를 두고 줄 끝으로 가서 students = [1,0,0,1]이 됩니다.
    2. 맨 앞 학생이 맨 위의 샌드위치를 두고 줄 끝으로 가서 students = [0,0,1,1]이 됩니다.
    3. 맨 앞 학생이 맨 위의 샌드위치를 가져가서 students = [0,1,1]이 되고 sandwiches = [1,0,1]이 됩니다.
    4. 맨 앞 학생이 맨 위의 샌드위치를 두고 줄 끝으로 가서 students = [1,1,0]이 됩니다.
    5. 맨 앞 학생이 맨 위의 샌드위치를 가져가서 students = [1,0]이 되고 sandwiches = [0,1]이 됩니다.
    6. 맨 앞 학생이 맨 위의 샌드위치를 두고 줄 끝으로 가서 students = [0,1]이 됩니다.
    7. 맨 앞 학생이 맨 위의 샌드위치를 가져가서 students = [1]이 되고 sandwiches = [1]이 됩니다.
    8. 맨 앞 학생이 맨 위의 샌드위치를 가져가서 students = []이 되고 sandwiches = []이 됩니다.
    9. 따라서 모든 학생들이 샌드위치를 먹을 수 있습니다.

예제 2

  • 입력: students = [1,1,1,0,0,1], sandwiches = [1,0,0,0,1,1]
  • 출력: 3

해결책

이 문제를 해결하기 위해서 다음 단계를 따라갈 수 있습니다:

  1. 각 샌드위치 타입의 수와 학생들의 선호도를 셉니다.
  2. 학생들이 줄을 돌면서 샌드위치를 가져가거나 줄 끝으로 가는 과정을 시뮬레이션합니다.
  3. 만약 더 이상 어떤 학생도 맨 위의 샌드위치를 원하지 않으면, 남은 학생 수를 반환합니다.

코드

def count_students_unable_to_eat(students, sandwiches):
    count0 = students.count(0)
    count1 = students.count(1)
    
    for sandwich in sandwiches:
        if sandwich == 0 and count0 > 0:
            count0 -= 1
        elif sandwich == 1 and count1 > 0:
            count1 -= 1
        else:
            break
            
    return count0 + count1

# 예제 입력
students1 = [1, 1, 0, 0]
sandwiches1 = [0, 1, 0, 1]

students2 = [1, 1, 1, 0, 0, 1]
sandwiches2 = [1, 0, 0, 0, 1, 1]

# 출력
print(count_students_unable_to_eat(students1, sandwiches1))  # 출력: 0
print(count_students_unable_to_eat(students2, sandwiches2))  # 출력: 3

 

 

 

 

오늘의 공부 키워드

  • 이진검색 트리(BST) 트리 최대 깊이 관련 내용 
  • 104 Maximum Depth of Binary Tree
  • 재귀함수의 개념

104 Maximum Depth of Binary Tree

문제 해석

이진 트리의 최대 깊이는 루트 노드부터 가장 멀리 있는 리프(leaf) 노드까지의 노드 수를 의미합니다. 즉, 루트 노드에서 가장 아래쪽에 있는 노드까지 가는 경로 중에서 가장 긴 경로의 노드 개수를 구하면 됩니다.

 

문제 예시

  1. 예시 1:
    • 입력: root = [3, 9, 20, null, null, 15, 7]
    • 출력: 3
    • 설명: 이 트리는 다음과 같습니다
    3
   / \
  9  20
     / \
    15  7

 

2. 예시 2:

  • 입력: root = [1, null, 2]
  • 출력: 2
  • 설명: 이 트리는 다음과 같습니다
    1
     \
      2

문제 풀이 방법

이 문제를 풀기 위해서는 재귀(Recursive) 함수를 사용하는 방법이 효과적입니다. 이진 트리의 각 노드에 대해 왼쪽 자식 노드와 오른쪽 자식 노드의 깊이를 재귀적으로 계산한 다음, 두 깊이 중 더 큰 값에 1을 더하면 현재 노드의 깊이가 됩니다.

 

코드설명

# 이진 트리의 노드를 나타내는 클래스
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

# 최대 깊이를 계산하는 함수
def maxDepth(root):
    # 만약 노드가 없으면 깊이는 0
    if root is None:
        return 0
    
    # 왼쪽과 오른쪽 자식 노드의 깊이를 재귀적으로 계산
    left_depth = maxDepth(root.left)
    right_depth = maxDepth(root.right)
    
    # 현재 노드의 깊이는 자식 노드 깊이 중 큰 값에 1을 더한 값
    return max(left_depth, right_depth) + 1

 

코드 설명

 

  1. TreeNode 클래스: 이 클래스는 이진 트리의 노드를 나타냅니다. 각 노드는 값(val), 왼쪽 자식 노드(left), 오른쪽 자식 노드(right)를 가집니다.
  2. maxDepth 함수: 이 함수는 주어진 이진 트리의 최대 깊이를 계산합니다.
    • 기본 조건: 만약 노드가 없으면(즉, root가 None이면) 깊이는 0입니다.
    • 재귀 호출: 왼쪽 자식 노드와 오른쪽 자식 노드의 깊이를 각각 재귀적으로 계산합니다.
    • 현재 노드의 깊이 계산: 왼쪽 깊이와 오른쪽 깊이 중 더 큰 값에 1을 더한 값을 반환합니다. 여기서 1을 더하는 이유는 현재 노드 자체도 깊이에 포함되기 때문입니다.

재귀 함수란?

재귀 함수는 자기 자신을 다시 호출하는 함수예요. 좀 더 쉽게 말하면, 함수 안에서 자기 자신을 또 다시 부르는 함수를 재귀 함수라고 해요.

 

 

예시로 이해하기

    3
   / \
  9  20
     /  \
    15   7

 

  1. 루트 노드 3에서 maxDepth(3)을 호출해요.
  2. maxDepth(3)는 maxDepth(9)와 maxDepth(20)을 호출해요.
  3. maxDepth(9)는 자식이 없어서 1을 반환해요.
  4. maxDepth(20)는 maxDepth(15)와 maxDepth(7)을 호출해요.
  5. maxDepth(15)와 maxDepth(7)은 자식이 없어서 각각 1을 반환해요.
  6. maxDepth(20)는 1 + max(1, 1) = 2를 반환해요.
  7. 마지막으로 maxDepth(3)는 1 + max(1, 2) = 3을 반환해요.

 

오늘의 회고

 

  • 이진 검색 트리의 문제에서 최대 깊이의 문제를 풀었다.
  • 재귀 함수의 개념에 대해서 익힐수 있었다.
  • 코드 리뷰라고 하더라도 문제를 이해하는게 정말 중요함을 느낀다.
  • 코딩테스트 문제만 풀지말고 기록도 남겨야 함을 느낀다.
  • LV1의 문제라지만 생각을 많이 하는 문제는 정말 좋은거 같다.

 

오늘의 공부 키워드

  • 이진검색 트리(BST) 구조 반전
  • 226 Invert Binary Tree

226 . Invert Binanay Tree

문제 해석

"Binary Tree Invert" 문제는 주어진 이진 트리(Binary Tree)의 구조를 반전시키는 문제입니다. 이진 트리란 각 노드가 최대 두 개의 자식을 가지는 트리입니다. 이 문제에서 반전이란 왼쪽 자식과 오른쪽 자식을 서로 바꾸는 것을 의미합니다.

 

    4
   / \
  2   7
 / \ / \
1  3 6  9

 

    4
   / \
  7   2
 / \ / \
9  6 3  1

 

 

문제 해결 방법

이 문제를 해결하기 위해, 다음의 단계들을 따릅니다:

  1. 기본 아이디어: 트리의 각 노드에 대해, 그 노드의 왼쪽 자식과 오른쪽 자식을 서로 교환합니다.
  2. 재귀 함수 사용: 트리 구조는 재귀적으로 정의되므로, 각 노드에 대해 재귀적으로 왼쪽과 오른쪽 자식을 교환하는 방법을 사용할 수 있습니다.

단계별 해결 방법

  1. 기본 케이스: 현재 노드가 None인 경우(즉, 트리가 비어 있거나 리프 노드의 자식인 경우), 그대로 None을 반환합니다.
  2. 재귀적 호출: 현재 노드의 왼쪽 자식과 오른쪽 자식을 서로 교환하고, 각각의 자식에 대해 다시 이 과정을 재귀적으로 수행합니다.

 

코드설명

 

from typing import Optional

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        # 트리가 비어 있는 경우
        if root is None:
            return None
        
        # 왼쪽과 오른쪽 자식을 교환합니다.
        root.left, root.right = root.right, root.left
        
        # 재귀적으로 각 자식에 대해 invertTree를 호출합니다.
        self.invertTree(root.left)
        self.invertTree(root.right)
        
        return root

 

코드 설명

  1. 주어진 이진 트리가 비어 있는지 확인합니다. 비어 있다면 None을 반환합니다.
  2. 현재 노드의 왼쪽 자식과 오른쪽 자식을 교환합니다.
  3. 왼쪽 자식과 오른쪽 자식에 대해 재귀적으로 invertTree 메서드를 호출하여 각각의 하위 트리를 반전시킵니다.
  4. 최종적으로 반전된 트리의 루트 노드를 반환합니다.

이 알고리즘은 모든 노드에 대해 한 번씩 방문하므로, 시간 복잡도는 O(n)이며, 여기서 n은 트리의 노드 수입니다.

 

오늘의 회고

  • 이진 검색 트리의 문제가 정말 많다는걸 느꼈다.
  • 이진 검색 트리를 정말 잘 익혀야 한다는 생각이 든다.
  • 여전히 개념에 대한 이해가 안되어 코드 리뷰 수준으로 문제를 푼점은 다시한번 아쉽게 된다.
  • 그래도 이렇게 기록으로 남기는건 나중에 다시한번 풀어보려는 이유 및
      어떻게 풀었는지 알기 위해서 기록을 남긴다.
  • LV1의 문제라지만 생각을 많이 하는 문제는 정말 좋은거 같다.

 

+ Recent posts