본문으로 바로가기
제품데스크톱 도구TASTECAD도면 확인TASTEFILES파일 관리TASTEFTP파일 전송TASTESSH원격 작업공간TASTEZIP압축과 해제개발 도구TASTECODERust 통합 개발 환경TASTESTUDIO통합 개발·테스트 환경TASTEETL데이터 통합(ETL)서버TASTEREMOTE원격 데스크톱 서버TASTEGEO공간정보 서버TASTEMAIL메일 작업공간시작하기다운로드문서구매모든 제품
마켓플레이스
소식
개발소식오늘의 개발 소식개발 문서프로그래밍 언어RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron알고리즘알고리즘 기초알고리즘 핵심알고리즘 심화실무 알고리즘
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스커뮤니티 안내
협업기술 전수홈페이지 구축데스크톱 앱 구축릴리스·결제 파이프라인판매 파트너문의
서비스원격 데스크톱설치 패키지 커스텀
TASTEDEV
제품

데스크톱 도구

TASTECAD복잡한 도면을 가볍게 열다TASTEFILES필요한 파일만, 가장 빠르게TASTEFTP파일이 오가는 가장 단정한 길TASTESSH서버와 나 사이, 더 단단한 연결TASTEZIP더 빠르게 묶고, 더 안전하게 풀다

개발 도구

TASTECODERust 앱을 편집 · 빌드 · 디버깅 · 테스트까지 한 창에서TASTESTUDIO편집부터 원격 테스트와 승인 기반 AI 수정까지TASTEETL값을 보며 데이터를 옮깁니다

서버

TASTEREMOTE우리 회사 서버로 운영하는 원격 데스크톱TASTEGEOGeoServer 호환 공간정보 서버를 Rust로 다시 세웁니다TASTEMAIL메일의 주도권을 다시 내 손에

시작하기

다운로드모든 제품 최신 판문서제품 사용법구매구독 · 영구 라이선스모든 제품모든 제품 한눈에
모든 제품
마켓플레이스소식
개발

소식

오늘의 개발 소식언어 · 프레임워크 · GitHub · AI 공식 발표개발 문서언어 · 프레임워크 · 알고리즘 안내서

프로그래밍 언어

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

프레임워크

프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular
서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express
앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron

알고리즘

알고리즘 기초복잡도 분석 · 정렬 · 탐색 · 기본 자료구조 · 트리와 힙알고리즘 핵심그래프 탐색 · 최단 경로와 최소 신장 트리 · 동적 계획법 · 탐욕 알고리즘 · 분할 정복 · 백트래킹알고리즘 심화문자열 알고리즘 · 수학과 정수론 · 비트 연산 · 구간 트리 · 유니온 파인드실무 알고리즘코딩 면접 풀이 전략 · LRU 캐시 · 레이트 리미터 · 일관된 해시
개발 문서 전체 보기
커뮤니티
프로젝트빌더와 작업 발견개발 로그결정과 시행착오프롬프트재사용 가능한 지시AI 도구 이슈Claude · Codex · Gemini 문제와 우회법쇼케이스완성된 결과커뮤니티 안내공개하고 함께 만드는 방식
협업
기술 전수Rust·egui 네이티브 앱 만들기홈페이지 구축10개 언어, 계정, 문서·다운로드데스크톱 앱 구축Rust·egui, WebView 없이릴리스·결제 파이프라인서명 · MSI·deb·rpm·AppImage · 해시판매 파트너소개하고 결제액의 30% 받기문의구축 · 제휴 · 투자 문의
서비스
원격 데스크톱브라우저로 내 컴퓨터에 접속설치 패키지 커스텀필요한 기능만, 설정은 미리
구매
KO
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
로그인
로그인
TASTEDEV

작은 도구부터, 더 좋은 개발까지.

support@tastedev.netTASTEDEV 후원하기
제품제품군구매문서다운로드마켓플레이스고객 지원
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스
정책개인정보처리방침이용약관구독 약관환불 정책커뮤니티 운영 정책
계정로그인가입하기
방문자
오늘
012345678901234567890123456789012345678901234567890123456789
어제
012345678901234567890123456789012345678901234567890123456789
누적 조회
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
상호
지엑스소프트
대표자
최영구
사업자등록번호
853-44-00368
주소
인천광역시 미추홀구 경인로 351 9층 V24
전화
+82-10-4404-1523
이메일
whitecalvin@tastedev.net
개인정보 보호책임자
최영구

© 2026 TASTEDEV제품 정보는 현재 검증된 개발 소스를 기준으로 합니다.출시·고도화 중

백트래킹 문서
백트래킹
백트래킹의 개념동작 원리구현복잡도연습 문제실무 활용
토론

백트래킹 안내서 · 5/6

연습 문제

백트래킹 문제는 겉모습이 달라도 "무엇을 한 단계로 볼 것인가, 어떤 조건에서 자를 것인가" 두 가지만 정하면 대부분 같은 틀로 풀립니다. 아래 네 문제를 직접 풀어 본 뒤 접근 방법과 풀이를 비교해 보세요.

문제 1: 괄호 짝 만들기

정수 n이 주어질 때, 여는 괄호와 닫는 괄호를 n개씩 써서 만들 수 있는 올바른 괄호 문자열을 모두 구하세요. 예를 들어 n = 2이면 (())와 ()()입니다.

접근: 한 글자씩 붙입니다. 여는 괄호는 n개보다 적게 썼을 때만, 닫는 괄호는 지금까지 연 괄호보다 적게 닫았을 때만 붙일 수 있습니다. 이 두 조건이 잘못된 문자열을 처음부터 막는 가지치기입니다.

def parentheses(n):
    out = []

    def dfs(s, opened, closed):
        if len(s) == 2 * n:
            out.append(s)
            return
        if opened < n:
            dfs(s + "(", opened + 1, closed)
        if closed < opened:
            dfs(s + ")", opened, closed + 1)

    dfs("", 0, 0)
    return out

print(parentheses(3))
# ['((()))', '(()())', '(())()', '()(())', '()()()']

문제 2: 격자에서 단어 찾기

글자가 적힌 2차원 격자와 단어 하나가 주어집니다. 상하좌우로 이웃한 칸을 따라가며 단어를 만들 수 있는지 판단하세요. 한 칸은 한 번만 쓸 수 있습니다.

접근: 첫 글자가 맞는 칸마다 탐색을 시작합니다. 현재 칸을 #으로 바꿔 사용 중임을 표시하고(선택), 네 방향으로 다음 글자를 찾은 뒤(탐색), 원래 글자로 되돌립니다(되돌리기). 글자가 다르면 즉시 돌아갑니다.

def exists(grid, word):
    rows, cols = len(grid), len(grid[0])

    def dfs(r, c, i):
        if i == len(word):
            return True
        if not (0 <= r < rows and 0 <= c < cols) or grid[r][c] != word[i]:
            return False
        saved, grid[r][c] = grid[r][c], "#"
        found = any(dfs(r + dr, c + dc, i + 1)
                    for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)))
        grid[r][c] = saved
        return found

    return any(dfs(r, c, 0) for r in range(rows) for c in range(cols))

board = [list("CAT"), list("OXD"), list("DEN")]
print(exists(board, "CODE"), exists(board, "COAT"))  # True False

문제 3: 중복 원소가 있는 순열

[1, 1, 2]처럼 같은 값이 섞인 목록의 서로 다른 순열만 구하세요. 결과에 같은 순열이 두 번 나오면 안 됩니다.

접근: 먼저 정렬합니다. 같은 깊이에서 같은 값을 두 번 고르면 같은 가지가 반복되므로, 바로 앞의 같은 값이 아직 쓰이지 않았다면 지금 값은 건너뜁니다. 결과를 집합에 넣어 중복을 지우는 것보다 탐색 자체가 줄어듭니다.

def unique_permutations(nums):
    nums = sorted(nums)
    used = [False] * len(nums)
    result, path = [], []

    def dfs():
        if len(path) == len(nums):
            result.append(path[:])
            return
        for i in range(len(nums)):
            if used[i]:
                continue
            if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
                continue
            used[i] = True
            path.append(nums[i])
            dfs()
            path.pop()
            used[i] = False

    dfs()
    return result

print(unique_permutations([1, 1, 2]))  # [[1, 1, 2], [1, 2, 1], [2, 1, 1]]

문제 4: 스도쿠 풀기

빈 칸이 0으로 표시된 9×9 스도쿠 판을 채우세요. 해가 하나 있다고 가정합니다.

접근: 행, 열, 상자마다 이미 쓴 숫자를 집합으로 들고 있으면 제약 검사가 O(1)입니다. 빈 칸 목록을 차례로 채우다가 넣을 숫자가 없으면 False를 돌려 앞 칸에서 다음 숫자를 시도하게 합니다. 해를 찾으면 True를 위로 전달해 더 이상 되돌리지 않습니다.

def solve_sudoku(board):
    rows = [set() for _ in range(9)]
    cols = [set() for _ in range(9)]
    boxes = [set() for _ in range(9)]
    empty = []
    for r in range(9):
        for c in range(9):
            d = board[r][c]
            if d:
                rows[r].add(d); cols[c].add(d); boxes[r // 3 * 3 + c // 3].add(d)
            else:
                empty.append((r, c))

    def fill(k):
        if k == len(empty):
            return True
        r, c = empty[k]
        b = r // 3 * 3 + c // 3
        for d in range(1, 10):
            if d in rows[r] or d in cols[c] or d in boxes[b]:
                continue
            board[r][c] = d
            rows[r].add(d); cols[c].add(d); boxes[b].add(d)
            if fill(k + 1):
                return True
            rows[r].remove(d); cols[c].remove(d); boxes[b].remove(d)
        board[r][c] = 0
        return False

    return fill(0)

더 빠르게 하려면 매번 남은 빈 칸 가운데 후보가 가장 적은 칸을 골라 채우세요(MRV). 어려운 퍼즐에서 탐색 노드가 크게 줄어듭니다.

정리

  • 한 단계의 단위(글자, 칸, 원소)와 가지치기 조건을 먼저 정하면 코드는 같은 틀로 쓰입니다.
  • 중복 해는 결과를 걸러 내기보다 같은 깊이에서 같은 선택을 막아 처음부터 만들지 않는 편이 좋습니다.
  • 해 하나만 필요하면 True를 돌려 탐색을 일찍 끝냅니다.
이 장에 대해 질문이 있나요?
이전 장복잡도다음 장실무 활용

댓글 0개

인기 댓글순최신순

로그인 · 로그인하면 댓글을 남길 수 있습니다.