백준 5624 - 좋은 수

Computer Science/Problem Solving

문제 설명

제한사항 및 입출력

풀이

문제가 굉장히 간단명료하다. 부연설명해보자면 수열에서 Ai 이전의 3개 숫자를 합해서 Ai를 만들 수 있다면 Ai는 좋은 수이다.(예제 똑바로 안 보고 바로 앞 3개로 풀이하다가 시간낭비한 사람...) 추가적으로 같은 값을 여러 번 써도 된다(인덱스 중복 허용) -> v+v+v, v+v+z 같은 조합도 가능.

 

v = (x + y) + z 에서 이항하면 v - z = x + y의 형태로 나타낼 수 있기 때문에 앞의 두 수의 합을 set에 저장한다면 앞의 숫자들을 순회하며 O(n)에 판별할 수 있다. 코드를 확인해보자

내 코드

import sys
input = sys.stdin.readline
mis = lambda: map(int, input().split())

n = int(input())
arr = [*mis()]

seen = set()       # 지금까지 앞부분에 등장한 값들의 집합
pair_sums = set()  # 앞부분 두 수의 합으로 만들 수 있는 값들의 집합

ans = 0
for v in arr:
    # 판정: v - z = x + y가능한지?
    if any((v - j) in pair_sums for j in seen):
        ans += 1
	
    # 갱신: v를 앞부분에 편입
    # v와 앞의 모든 x를 짝지어 두 수 합을 추가
    pair_sums.update(v + x for x in seen)
    
    # v를 두 번 사용하는 경우
    pair_sums.add(v + v)
    seen.add(v)

print(ans)

앞에 나온 숫자들을 순회하며 두 수의 합들을 확인하고 현재 값을 만들 수 있는지 확인한다.

이후 앞에 나온 숫자들에 현재 숫자를 더하며 두 수의 조합을 만들어서 pair_sums에 저장해주고 현재 값 두 개를 사용하는 경우도 함께 저장해준다.

 

구현 자체는 간단해서 크게 설명할만한 부분이 없다. 로직을 생각해서 숫자 조합을 O(n)으로 판별하는 것이 중요한 문제인 것 같다. 모든 세 수의 조합을 모두 계산하기에는 O(n^3)이 나오기 때문에 n <= 5000 이라는 제한 안에서는 시간 안에 해결할 수 없다.

시간복잡도

모든 수를 순회하며(n) 해당 수의 이전 모든 값 확인(~n), 현재 수를 앞의 모든 수와 더하여 새로운 조합 만들기(~n)

-> O(n^2) 

고찰

투 포인터로도 풀이할 수 있다! 시간초과가 날 줄 알았는데 아슬아슬하게 통과한다.

import bisect
import sys
mis = lambda: map(int, input().split())
input = sys.stdin.readline

n = int(input())
arr = [*mis()]

seen = set()          # 앞부분의 값들
seen_sorted = []      # 정렬된 고유값 리스트

def has_two_sum(sorted_vals, target):
    # 같은 값을 두 번 써도 되므로 l<=r 허용
    l, r = 0, len(sorted_vals) - 1
    while l <= r:
        s = sorted_vals[l] + sorted_vals[r]
        if s == target:
            return True
        if s < target:
            l += 1
        else:
            r -= 1
    return False

ans = 0
for v in arr:
    # v = j + (x+y) 판정
    good = False
    for j in seen:
        if has_two_sum(seen_sorted, v - j):
            good = True
            break
    if good:
        ans += 1

    # v를 앞부분에 편입(정렬된 고유값 유지)
    if v not in seen:
        seen.add(v)
        bisect.insort(seen_sorted, v)

print(ans)

i번째 값 v를 처리할 때, 앞에서 나온 서로 다른 값들(집합 seen)만으로 만들어진 정렬 리스트 seen_sorted에서 어떤 j 에 대해 v - j가 두 수 합으로 만들 수 있으면 v는 좋은 수이다.

 

v - z = x + y를 투 포인터로 검사하는 로직이다. “같은 값을 여러 번 써도 된다” 조건 때문에, 두 포인터는 l <= r 로 둬서 x==y도 고려해서 풀이한다.

 

투 포인터 풀이의 시간복잡도는 다음과 같다.

U_i를 i번째 단계에서의 서로 다른 앞 값 개수, U_max를 max_i U_i (최대 고유 개수)라고 했을 때

 

 

바깥 루프 -> O(U_i) 번

매번 has_two_sum(seen_sorted, v - j) 판정 비용 -> O(U_i²) (seen 내부에서 시행되기 때문)

 

갱신하는데 bisect.insort(seen_sorted, v) → O(U_i)이므로, 최악 O(N³)의 시간복잡도가 든다.

 

'Computer Science > Problem Solving' 카테고리의 다른 글

백준 20924 - 트리의 기둥과 가지  (0) 2025.09.04
백준 9421 - 소수상근수  (0) 2025.09.03
백준 14607 - 피자 (Large)  (0) 2025.08.26
백준 1005 - ACM Craft  (0) 2025.08.25
백준 12033 - 김인천씨의 식료품가게 (Small)  (0) 2025.08.22
'Computer Science/Problem Solving' 카테고리의 다른 글
  • 백준 20924 - 트리의 기둥과 가지
  • 백준 9421 - 소수상근수
  • 백준 14607 - 피자 (Large)
  • 백준 1005 - ACM Craft
hojoo
hojoo
그냥 개발이 즐거운 사람
  • hojoo
    dev_record
    hojoo
  • 전체
    오늘
    어제
    • 분류 전체보기 (82)
      • Study (0)
        • 모든 개발자를 위한 HTTP 웹 기본 지식 (0)
        • Real MySQL 8.0 (0)
        • 친절한 SQL 튜닝 (0)
        • 도메인 주도 개발 시작하기 (0)
        • 대규모 시스템 설계 기초 (0)
      • Computer Science (66)
        • Problem Solving (30)
        • Data Structure (4)
        • Spring Boot (13)
        • DB (1)
        • Java (4)
        • OS (3)
        • Server (2)
        • Tech (0)
      • Security (16)
        • Reversing (15)
        • Assembly (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    리버싱
    12033
    bean
    자료구조
    n+1
    Spring boot
    Lena tutorial
    16946
    HTTP
    서버 증설 횟수
    15973
    DP
    PE header
    Header
    소수상근수
    백준
    리버싱 핵심원리
    레나 튜토리얼
    Reversing
    21278
    13265
    n^2 배열 자르기
    x64dbg
    9421
    DB
    2539
    servlet
    프로그래머스
    dreamhack.io
    19622
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
hojoo
백준 5624 - 좋은 수
상단으로

티스토리툴바