본문으로 바로가기
제품데스크톱 도구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제품 정보는 현재 검증된 개발 소스를 기준으로 합니다.출시·고도화 중

코딩 면접 풀이 전략 문서
코딩 면접 풀이 전략
코딩 면접의 개념문제 풀이 절차패턴 구현복잡도 설명과 트레이드오프패턴 연습 문제실전 준비와 시험 환경
토론

코딩 면접 풀이 전략 안내서 · 3/6

패턴 구현

이 장에서는 면접에서 가장 자주 쓰는 세 패턴인 투 포인터, 해시 맵, 슬라이딩 윈도우를 Python으로 구현합니다. 그중 핵심인 슬라이딩 윈도우는 한 줄씩 설명한 뒤 C++, Java, TypeScript로도 옮겨, 언어가 바뀌어도 같은 생각이 어떻게 이어지는지 보여 줍니다.

투 포인터: 정렬된 배열의 중복 제거

같은 방향으로 움직이는 두 포인터입니다. read는 모든 원소를 읽고, write는 다음에 남길 값을 쓸 자리를 가리킵니다. 추가 배열 없이 제자리에서 정리하므로 공간은 O(1)입니다.

def dedupe_sorted(nums: list[int]) -> int:
    """정렬된 nums에서 중복을 제자리에서 지우고 남은 개수를 돌려준다."""
    write = 0
    for read in range(len(nums)):
        if read == 0 or nums[read] != nums[read - 1]:
            nums[write] = nums[read]
            write += 1
    return write


data = [1, 1, 2, 3, 3, 3, 5]
count = dedupe_sorted(data)
print(count, data[:count])  # 4 [1, 2, 3, 5]

해시 맵: 합이 target인 두 원소의 위치

정렬되지 않은 배열에서 합이 target인 두 원소의 인덱스를 찾습니다. 지금 값 x에 대해 필요한 짝은 target - x이므로, 지금까지 본 값의 위치를 딕셔너리에 저장해 두면 한 번 훑는 동안 답을 찾을 수 있습니다. 정렬하면 원래 인덱스를 잃기 때문에 이 문제에서는 투 포인터보다 해시 맵이 알맞습니다.

def pair_indices(nums: list[int], target: int) -> tuple[int, int] | None:
    index_of: dict[int, int] = {}
    for i, x in enumerate(nums):
        need = target - x
        if need in index_of:
            return index_of[need], i
        index_of[x] = i  # 짝을 확인한 뒤에 넣어야 자기 자신과 짝이 되지 않는다
    return None


print(pair_indices([8, 3, 5, 11, 2], 13))  # (0, 2)
print(pair_indices([1, 2], 10))            # None

슬라이딩 윈도우: 중복 없는 가장 긴 구간

문자열에서 같은 문자가 두 번 나오지 않는 가장 긴 연속 구간의 길이를 구합니다. 창 [left, right] 안에는 중복 문자가 없다는 불변식을 유지하면서 right를 한 칸씩 늘립니다.

def longest_unique_window(s: str) -> int:
    last_seen: dict[str, int] = {}   # 문자 -> 마지막으로 본 위치
    left = best = 0
    for right, ch in enumerate(s):
        if last_seen.get(ch, -1) >= left:
            left = last_seen[ch] + 1  # 창 안의 중복을 건너뛴다
        last_seen[ch] = right
        best = max(best, right - left + 1)
    return best


for text in ["tastedev", "aaaa", "interview", ""]:
    print(repr(text), longest_unique_window(text))
# 'tastedev' 5 / 'aaaa' 1 / 'interview' 6 / '' 0

한 줄씩 보면 다음과 같습니다.

  • last_seen은 각 문자를 마지막으로 본 위치를 기억합니다. 문자를 지우는 대신 위치를 기억하므로 왼쪽 끝을 한 번에 건너뛸 수 있습니다.
  • last_seen.get(ch, -1) >= left는 "이 문자가 지금 창 안에 이미 있는가"를 뜻합니다. 창 왼쪽 바깥에서 본 위치는 무시해야 하므로 left와 비교하는 부분이 중요합니다.
  • 중복이 있으면 left를 그 문자의 직전 위치 바로 다음으로 옮깁니다. left는 앞으로만 움직이므로 전체 이동은 n번을 넘지 않습니다.
  • 위치를 갱신한 뒤 현재 창 길이 right - left + 1로 최댓값을 갱신합니다.

전체 시간은 O(n)이고, 공간은 서로 다른 문자 수 σ에 대해 O(min(n, σ))입니다. 면접에서는 left와 비교하는 조건을 빠뜨려 "abba" 같은 입력에서 왼쪽 끝이 뒤로 가는 버그가 자주 나옵니다. 이 입력의 답은 2입니다.

C++

std::unordered_map으로 마지막 위치를 저장합니다. 문자열 길이는 size_t이므로 인덱스를 int로 바꿀 때 형 변환을 분명히 합니다.

#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>

int longestUniqueWindow(const std::string& s) {
    std::unordered_map<char, int> lastSeen;
    int left = 0, best = 0;
    for (int right = 0; right < static_cast<int>(s.size()); ++right) {
        auto it = lastSeen.find(s[right]);
        if (it != lastSeen.end() && it->second >= left) {
            left = it->second + 1;
        }
        lastSeen[s[right]] = right;
        best = std::max(best, right - left + 1);
    }
    return best;
}

int main() {
    std::cout << longestUniqueWindow("tastedev") << '\n';  // 5
    std::cout << longestUniqueWindow("abba") << '\n';      // 2
}

Java

HashMap<Character, Integer>를 씁니다. get이 null을 돌려줄 수 있으므로 Integer로 받아 확인합니다.

import java.util.HashMap;
import java.util.Map;

public class LongestUniqueWindow {
    static int longestUniqueWindow(String s) {
        Map<Character, Integer> lastSeen = new HashMap<>();
        int left = 0, best = 0;
        for (int right = 0; right < s.length(); right++) {
            char ch = s.charAt(right);
            Integer prev = lastSeen.get(ch);
            if (prev != null && prev >= left) {
                left = prev + 1;
            }
            lastSeen.put(ch, right);
            best = Math.max(best, right - left + 1);
        }
        return best;
    }

    public static void main(String[] args) {
        System.out.println(longestUniqueWindow("tastedev")); // 5
        System.out.println(longestUniqueWindow("abba"));     // 2
    }
}

TypeScript

Map<string, number>를 씁니다. Array.from(s)로 나누면 이모지처럼 두 코드 단위로 된 문자도 한 글자로 다룹니다.

function longestUniqueWindow(s: string): number {
  const lastSeen = new Map<string, number>();
  const chars = Array.from(s);
  let left = 0;
  let best = 0;
  for (let right = 0; right < chars.length; right++) {
    const prev = lastSeen.get(chars[right]);
    if (prev !== undefined && prev >= left) left = prev + 1;
    lastSeen.set(chars[right], right);
    best = Math.max(best, right - left + 1);
  }
  return best;
}

console.log(longestUniqueWindow("tastedev")); // 5
console.log(longestUniqueWindow("abba")); // 2

C++의 char와 Java의 charAt은 바이트나 UTF-16 코드 단위 기준이므로, 한글이나 이모지가 섞인 입력을 다룰 때는 이 점을 면접관에게 짚어 두면 좋습니다. 대부분의 면접 문제는 영문 소문자나 ASCII로 입력을 제한하므로, 그럴 때는 크기 26 또는 128인 배열로 해시 맵을 대신해 상수 배를 줄일 수도 있습니다.

정리

투 포인터는 정렬이나 제자리 정리에, 해시 맵은 "이미 본 값"을 빠르게 찾을 때, 슬라이딩 윈도우는 연속 구간의 최적값을 구할 때 씁니다. 세 패턴 모두 핵심은 반복문이 도는 동안 지켜야 할 불변식을 정하고, 포인터가 앞으로만 움직이게 만드는 것입니다. 언어를 바꿔도 이 뼈대는 그대로이며, 달라지는 것은 해시 맵 API와 문자 단위 정도입니다.

이 장에 대해 질문이 있나요?
이전 장문제 풀이 절차다음 장복잡도 설명과 트레이드오프

댓글 0개

인기 댓글순최신순

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