Skip to content

Conversation

@Mingguriguri
Copy link
Collaborator

🌱WIL

이번 한 주의 소감을 작성해주세요!

  • 이번 주에는 꾸준히 문제를 풀지 못한 점이 아쉽다. 월요일과 토요일에 몰아서 문제를 풀었는데, 알고리즘 스터디뿐만 아니라 다른 프로젝트에서도 의욕이 다소 떨어져 모든 방면에서 좋은 성과를 내지 못한 것 같다. 다음 주에는 꾸준히 하루에 4문제 이상을 풀고, 시간이 된다면 Python 풀이를 Java로도 변환해 풀어보고 싶다.
  • 이번 주 발제 및 과제 문제의 주제는 투포인터였다. #2470. 두 용액 문제는 비슷한 유형을 여러 번 풀어본 덕분에 비교적 수월하게 해결할 수 있었다. 그러나 #2473. 세 용액 문제는 세 개의 값을 찾아야 해서 처음에 좀 헤맸다. 처음 접근할 때는 세 개의 포인터(left, mid, right)를 동시에 관리하려 했지만, 문제를 풀다 보니 이 방식은 일부 조합을 시도조차 하지 않는다는 단점이 있다는 것을 알게 되었다. 이 문제를 통해, 세 값을 구해야 할 때는 하나의 값을 고정(i)하고, 나머지 두 값을 투포인터로 관리해야 한다는 점을 배웠다. 또, 다른 분들의 블로그 코드를 참고하다 보니 시간 초과가 발생하는 경우도 있었는데, 그 원인을 분석해볼 수 있었다.
  • #5107. 마니또 문제는 잊고 있었던 유니온 파인드 알고리즘을 복습할 수 있는 좋은 기회였다. 기존에는 숫자로 표현된 그래프를 주로 다뤘지만, 이번 문제는 "이름"을 기반으로 접근해야 해서 처음에는 많이 헷갈렸다. 그래도 덕분에 유니온 파인드 개념을 다시 정리할 수 있어 의미 있는 시간이었다.

🚀주간 목표 문제 수: 3개

푼 문제


백준 #2470. 두 용액: 투포인터 / 골드5

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 전체 용액의 수 N과 용액의 특성값을 저장할 리스트 liquid를 입력받고 정렬한다.

  2. left, right 투 포인터를 초기화한다.

  3. answeranswer_liquid의 초기값을 설정한다.

  4. leftright가 교차할 때까지 아래 과정을 반복한다.

    1. 두 수의 합을 temp에 저장해둔다.
    2. temp가 0에 더 가까우면 정답을 갱신한다
    3. temp가 음수이면 left += 1, temp가 양수이면 right -= 1로 포인터를 이동한다.
  5. while 반복문 종료 후 정답을 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline

N = int(input())  # 전체 용액의 수
liquid = sorted(map(int, input().split()))

left = 0
right = N - 1

# 초기값 설정
answer = abs(liquid[left] + liquid[right])
answer_liquid = [liquid[left], liquid[right]]

while left < right:
    temp = liquid[left] + liquid[right]
    # 합이 0에 더 가까우면 정답 갱신
    if abs(temp) < answer:
        answer = abs(temp)
        answer_liquid = [liquid[left], liquid[right]]
    # 포인터 이동
    if temp < 0:
        left += 1
    else:
        right -= 1

print(answer_liquid[0], answer_liquid[1])

💡TIL

배운 점이 있다면 입력해주세요

  • 처음 문제를 보고 "정렬 → 투 포인터" 전략은 바로 떠올렸지만, 세세한 부분에서 실수가 많았다. 문제에 사용하는 필수 조건을 설정하는 것이나, 조건문의 위치를 설정하는 것, 초기값을 설정해주는 것 등등 모두 신경써서 풀이해야 할 것 같다.

백준 #2473. 세 용액: 투포인터 / 골드3

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력받은 용액 배열을 오름차순 정렬
  2. for문을 돌면서 첫 번째 수(i)를 고정
  3. i 다음 인덱스를 left로, 마지막 인덱스를 right로 설정
  4. 투 포인터로 합을 계산하고 갱신
  5. leftright가 교차하면 종료

🚩제출한 코드

import sys
input = sys.stdin.readline

N = int(input())  # 전체 용액의 수
liquid = sorted(map(int, input().split()))

left = 0
right = N-1
mid = (left + right) // 2
answer = abs(liquid[left] + liquid[mid] + liquid[right])
answer_liquid = [liquid[left], liquid[mid], liquid[right]]

for i in range(N-2):
    left = i + 1
    right = N - 1

    while left < right:
        temp = liquid[i] + liquid[left] + liquid[right]
        if abs(temp) < answer:
            answer = abs(temp)
            answer_liquid = [liquid[i], liquid[left], liquid[right]]
        if temp < 0:
            left += 1
        else:
            right -= 1

print(*answer_liquid)

💡TIL

배운 점이 있다면 입력해주세요

  • 처음에 접근할 때에는 **“한 번에 3개의 포인터(left, mid, right)를 동시에 관리”**하려고 했다. 이렇게 하면 일부 조합의 경우를 시도하지 않고 넘어가기 때문에 정확한 답을 낼 수 없다는 것을 알게 되었다. 이 문제처럼 3개의 값을 구해야 하는 투포인터의 유형의 경우 하나를 고정값(ex. i )으로 두고, 나머지 2개를 포인터로 설정해야 한다는 것을 알게 되었다.
  • sys.maxsize 를 사용하면 시간초과가 날 수 있다는 것을 알게 되었다.
  • 배열 앞에 *를 붙여 출력하면 한 칸씩 간격을 두고 출력할 수 있다.

백준 #5107. 마니또: 그래프 / 실버1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력을 받는다. (N = 0일 때 종료)
  2. 이름을 번호로 매핑하는 manito 딕셔너리를 만든다.
  3. 유니온 파인드를 통해 관계를 합친다.
  4. parent 배열을 set으로 변환해 그룹 수를 세고 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline

# Find 연산(같은 집합에 속하는지 확인하기 위한 함수)
def find(a):
    if a != parent[a]:
        parent[a] = find(parent[a]) # 경로 압축
    return parent[a]

# Union 연산(두 집합을 합치기 위한 함수)
def union(a, b):
    p_a = find(a)
    p_b = find(b)

    if p_a > p_b: # 값이 더 작은 쪽을 부모로 설정
        parent[p_a] = p_b
    else:
        parent[p_b] = p_a

tc_num = 0  # 테스트케이스 개수
while True:
    N = int(input())
    parent = [i for i in range(N + 1)]  # 초기: 각 원소가 자기 자신을 부모로 가짐
    manito = {}
    tc_num += 1  # 테스트케이스 업데이트

    if N == 0: # 입력 종료
        break

    for _ in range(N):
        from_p, to_p = input().split()
        # manito에 번호 부여
        if from_p not in manito:
            manito[from_p] = len(manito) + 1
        if to_p not in manito:
            manito[to_p] = len(manito) + 1
        # 합집합 연산
        union(parent[manito[from_p]], parent[manito[to_p]])
        
    parent = set(parent)

    print(tc_num, len(parent)-1) # 0이 포함되어 있으므로 1 빼주어야 함

💡TIL

배운 점이 있다면 입력해주세요

  • 문제를 처음에 봤을 때 집합의 개수를 구하는 문제인 것 같아서 “유니온 파인드”로 풀 수 있을 것 같다고 생각이 들었다. 하지만 중간에 DFS로 풀어야 하나 하면서 갈피를 잃었다.. 심지어 유니온 파인드도 find와 union 함수를 어떻게 구현했었는지 까먹어서 복습이 필요했다. 이 문제를 통해서 유니온과 파인드 연산을 어떻게 해야 하는지 다시 리마인드 할 수 있었다.
  • 사실 N이 20이하로 매우 작아서 DFS로 풀어도 된다. 하지만 그래도 시간 복잡도 관점에서는 유니온 파인드가 더 깔끔하고 빠르다!

Copy link
Member

@YoonYn9915 YoonYn9915 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 발제 문제와 과제 문제 모두 잘 풀어주신것 같습니다.

과제 문제는 N이 5000개까지이므로 O(N log N)의 시간복잡도를 사용할 수 있는 문제였습니다. 따라서 선형으로 O(N) 시간복잡도를 써서 세 용액중 하나를 고정시켜놓고, 발제문제에서 사용한 투 포인터 알고리즘으로 O(log N) 시간 복잡도를 써서 나머지 용액 중 절댓값이 0에 가장 가까운 두 용액을 찾으면 되는 문제였습니다.

한 주 수고하셨습니다!!!

Comment on lines +13 to +25
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 i를 고정한 뒤에 left는 0부터 right는 N-1부터 시작하게 했는데 민정님 코드 보니까 left를 i+1로 해도 되겠네요.
민정님이 리뷰 남겨주신 아래 부분도 left가 0부터 시작하니 i가 left나 right와 같아질 수도 있어서 추가한 거거든요.

  if left == i:
            left = i + 1
            continue
        elif right == i:
            right = i - 1
            continue

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇군요!! 윤상님처럼 접근할 수 있다는 점 참고해야겠네요!!

Copy link
Collaborator

@zaqquum zaqquum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번주 고생하셨습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 세 용액 총합의 최소값을 INF로 설정했는데 민정님은 첫번째 경우의 합으로 설정하셨네요. 초기화는 필수가 아닌 이상 저는 설정하지 않고 그냥 사용했던 것 같습니다.
그래도 민정님처럼 중간값, 세 용액 조합 리스트 같이 아래에서 새로 대입하는 변수지만 위에서 초기화 하고 사용하는 것이 가독성과 변수 활용에 용이해 보이네요.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다!

@Mingguriguri Mingguriguri merged commit f486c10 into main Apr 28, 2025
@github-actions
Copy link

🔥2025-04 챌린지 진행 상황

👉 그래프

  • YoonYn9915: 1개 ❌
  • Mingguriguri: 3개 ❌
  • zaqquum: 4개 ❌
  • learntosurf: 3개 ❌

👉 DP

  • YoonYn9915: 3개 ❌
  • Mingguriguri: 6개 ✅
  • zaqquum: 4개 ❌
  • learntosurf: 0개 ❌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants