✅ Ping 테스트란?

Ping 테스트(Ping Test)는 네트워크에서 특정 대상(서버, 장비, 호스트 등)이 정상적으로 통신 가능한지 확인하는 기본적인 네트워크 진단 방법이야.

Ping 테스트는 ICMP(Internet Control Message Protocol) Echo Request 및 Echo Reply 메시지를 이용해
목적지까지의 응답 여부, 네트워크 지연 시간(Latency), 패킷 손실(Packet Loss) 등을 측정할 수 있어.

💡 쉽게 말하면?
👉 네트워크 연결이 정상인지 확인하는 가장 기본적인 테스트 방법!


📌 Ping 테스트의 중요성

1. 네트워크 연결 상태 확인

  • 대상 장비(서버, 네트워크 장비, PC 등)가 응답하는지 확인 가능
  • 장비가 꺼져 있거나 네트워크 장애가 있으면 응답 없음

2. 네트워크 지연 시간(Latency) 측정

  • **Ping 응답 시간(ms, milliseconds)**으로 목적지까지의 왕복 시간 측정
  • 네트워크 속도 저하나, 과부하 발생 여부를 판단 가능

3. 패킷 손실(Packet Loss) 확인

  • 네트워크 품질이 나쁠 경우 Ping 요청이 일부 손실될 수 있음
  • 손실률(%)이 높으면 네트워크 불안정, 라우팅 문제, 장애 가능성

4. 네트워크 경로 문제 진단

  • 특정 네트워크 구간에서 응답이 없으면 해당 구간에서 문제 발생 가능성

5. 방화벽 및 접근 제한 확인

  • 특정 IP 또는 포트에서 ICMP 요청을 차단하면 Ping 응답이 없을 수도 있음

📌 Ping 테스트의 결과 분석

Ping 명령어 실행 후 결과를 해석하는 방법을 알아보자.

1️⃣ 정상적인 응답 (Success)

$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=23.4 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=118 time=24.1 ms

정상적인 연결 상태

  • 목적지(8.8.8.8)와 네트워크 연결이 정상
  • 응답 시간(time=23.4 ms)을 확인하여 네트워크 속도 확인 가능

2️⃣ 응답 없음 (Request Timed Out)

$ ping 192.168.1.100
Request timed out.
Request timed out.

문제 발생 가능성

원인 설명

대상 장비 꺼짐 목적지 장비가 꺼져 있거나 네트워크 연결이 끊어짐
방화벽 설정 ICMP 요청이 차단됨 (방화벽 규칙 확인 필요)
네트워크 장애 중간 네트워크 장비(라우터, 스위치)에서 연결 불가

3️⃣ 높은 지연 시간 (High Latency)

$ ping 8.8.8.8
64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=480 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=118 time=502 ms

문제 발생 가능성

원인 설명

네트워크 과부하 트래픽이 많아 응답 시간이 증가
ISP 문제 인터넷 서비스 제공업체(ISP)에서 대역폭 제한
거리 문제 목적지가 물리적으로 너무 멀어 응답 시간이 증가

4️⃣ 패킷 손실 (Packet Loss)

$ ping -c 5 8.8.8.8
5 packets transmitted, 3 received, 40% packet loss, time 4000ms

문제 발생 가능성

원인 설명

네트워크 불안정 무선 네트워크(Wi-Fi) 신호 약함
네트워크 장비 문제 스위치, 라우터 장애 또는 포트 오류
네트워크 공격 (DDoS) 네트워크 트래픽이 과부하 상태

📌 Ping 테스트를 활용한 네트워크 문제 해결

Ping을 통해 네트워크 문제를 진단하는 방법을 단계별로 설명할게.

1️⃣ 특정 장비(서버, PC)와 연결 확인

ping 192.168.1.1  # 게이트웨이 확인
ping 8.8.8.8      # 외부 네트워크 확인

응답이 있으면 → 네트워크 연결 정상
응답이 없으면 → 장비 꺼짐, 네트워크 장애, 방화벽 차단 가능성


2️⃣ 네트워크 경로 확인 (Traceroute)

traceroute 8.8.8.8  # Linux/macOS
tracert 8.8.8.8     # Windows

✅ 특정 구간에서 응답이 없으면 해당 네트워크 경로에서 문제 발생 가능성


3️⃣ 특정 패킷 크기 테스트 (MTU 확인)

ping -M do -s 1472 8.8.8.8  # MTU 1500 바이트 테스트

MTU 문제가 있으면 패킷 손실 가능성이 있음 (터널링, VPN 환경에서 중요)


📌 Ping 테스트의 한계

Ping은 기본적인 네트워크 진단 도구이지만, 완벽한 진단 도구는 아니야.

ICMP 차단 가능성

  • 방화벽에서 ICMP 패킷 차단 시 Ping 응답이 없을 수도 있음
    네트워크 성능 측정 한계
  • Ping은 단순 응답 시간 측정이므로 실제 애플리케이션 성능을 보장하지 않음
    트래픽 우선순위 문제
  • 일부 네트워크 장비는 ICMP 트래픽을 낮은 우선순위로 처리하여 부정확한 결과가 나올 수도 있음

대체 도구

도구 기능

Traceroute (traceroute, tracert) 네트워크 경로 확인
MTR (My Traceroute) Ping + Traceroute 통합 테스트
iPerf 네트워크 속도 테스트
Wireshark 패킷 캡처 및 분석

🔥 결론

  • Ping 테스트는 네트워크 연결 상태, 지연 시간, 패킷 손실 등을 확인하는 기본적인 네트워크 진단 방법.
  • ICMP Echo Request/Reply를 이용하여 대상 장비가 응답하는지 확인 가능.
  • 응답 없음(Request Timed Out) → 장비 꺼짐, 방화벽 차단, 네트워크 장애 가능성
  • 높은 지연 시간(High Latency) → 네트워크 과부하, ISP 문제 가능성
  • 패킷 손실(Packet Loss) → 무선 신호 약함, 네트워크 장애 가능성
  • Traceroute, MTR, Wireshark 같은 추가 네트워크 분석 도구와 함께 사용하면 문제 해결에 더 효과적!

✅ OSI 7 계층에서 데이터 흐름 방식

OSI 7 계층(Open Systems Interconnection Model)은 네트워크에서 데이터가 전송되는 과정을 계층별로 나누어 설명하는 모델이야.
이 모델을 기반으로 데이터가 어떻게 송신자(발신)에서 수신자(목적지)로 이동하는지 설명해줄게.


📌 OSI 7 계층 개요

OSI 7 계층은 애플리케이션 계층(L7)에서 데이터가 생성되어 물리 계층(L1)로 내려가 전송되며,
수신 측에서는 반대로 L1 → L7 순서로 데이터를 복원
하는 방식으로 작동해.

✅ OSI 7 계층과 주요 기능

계층 이름 역할

L7 애플리케이션 계층 (Application Layer) 사용자와 직접 상호작용 (HTTP, FTP, SMTP)
L6 표현 계층 (Presentation Layer) 데이터 변환(인코딩/디코딩, 암호화)
L5 세션 계층 (Session Layer) 연결 설정 및 유지 (세션 관리)
L4 전송 계층 (Transport Layer) 신뢰성 있는 데이터 전송 (TCP/UDP)
L3 네트워크 계층 (Network Layer) IP 주소 기반 패킷 라우팅
L2 데이터 링크 계층 (Data Link Layer) MAC 주소 기반 프레임 전송
L1 물리 계층 (Physical Layer) 0과 1의 전기 신호/광신호 변환 및 전송

💡 쉽게 말하면?

  • L7~L5 (애플리케이션 계층): 데이터를 생성하고 사용자와 상호작용
  • L4 (전송 계층): 데이터 흐름을 제어하고 신뢰성을 보장
  • L3~L1 (네트워크 계층 & 물리 계층): 데이터를 실제로 전송

📌 OSI 7 계층에서 데이터 흐름 방식

데이터는 송신 측에서 L7 → L1 방향으로 내려가고, 수신 측에서 L1 → L7 방향으로 올라옴.
각 계층에서 데이터가 어떻게 변환되고 이동하는지 설명할게.


🚀 1. 데이터 생성 (L7 - 애플리케이션 계층)

사용자가 요청을 생성하고 데이터를 만들어 전송 준비
예제: 사용자가 웹 브라우저에서 "www.google.com" 접속 요청

역할

  • HTTP, FTP, SMTP 등 애플리케이션 프로토콜 사용
  • 데이터를 텍스트, 이미지, 파일 등의 형식으로 생성
  • 예: 웹 브라우저(HTTP 요청), 이메일 전송(SMTP)

데이터 형태: 메시지(Message)


🚀 2. 데이터 변환 (L6 - 표현 계층)

데이터를 네트워크에서 전송할 수 있는 형태로 변환 (인코딩, 암호화, 압축)

역할

  • 텍스트 인코딩 (UTF-8, ASCII)
  • 압축 (JPEG, PNG, ZIP)
  • 암호화 (SSL/TLS, AES, RSA)
  • 예: 웹사이트 HTTPS 요청 시 TLS 암호화

데이터 형태: 메시지(Message) (암호화된 데이터일 수도 있음)


🚀 3. 연결 설정 (L5 - 세션 계층)

통신 세션을 설정하고 관리 (연결 유지, 다중 연결 지원)

역할

  • 세션 생성 및 유지 (TCP 3-Way Handshake)
  • 세션 복구 (끊긴 연결 재설정)
  • 예: 로그인 유지, VoIP(음성 통화) 연결 지속

데이터 형태: 메시지(Message)


🚀 4. 데이터 분할 및 전송 방식 결정 (L4 - 전송 계층)

데이터를 작은 조각(Segment)으로 나누고, 신뢰성을 보장할지 결정 (TCP/UDP 사용)

역할

  • TCP (신뢰성 보장) → 오류 검사, 패킷 재전송 (웹, 이메일)
  • UDP (빠른 전송) → 속도 우선, 오류 검증 없음 (VoIP, 스트리밍)
  • 포트 번호 (80, 443, 22 등)로 프로세스 구분

데이터 형태: 세그먼트(Segment)


🚀 5. 패킷 생성 및 라우팅 (L3 - 네트워크 계층)

IP 주소를 기반으로 패킷을 생성하고 최적의 경로를 찾음

역할

  • 목적지 IP 주소를 확인하고 패킷 라우팅
  • 라우터를 통해 경로 설정 (BGP, OSPF, RIP)
  • TTL(Time to Live) 설정하여 패킷이 무한히 떠돌지 않도록 함

데이터 형태: 패킷(Packet)


🚀 6. MAC 주소 기반 데이터 전송 (L2 - 데이터 링크 계층)

MAC 주소를 기반으로 목적지 장비까지 데이터 전달 (LAN, 스위치, VLAN 사용)

역할

  • MAC 주소 기반 프레임 생성 및 전달
  • 이더넷(Ethernet), Wi-Fi, PPP, VLAN 적용
  • 스위치가 프레임을 목적지 MAC 주소로 전달
  • 예: 회사 내부 네트워크(LAN)에서 PC → 라우터로 전송

데이터 형태: 프레임(Frame)


🚀 7. 실제 데이터 전송 (L1 - 물리 계층)

0과 1의 디지털 데이터를 전기 신호/광신호로 변환하여 전송

역할

  • 이더넷 케이블(UTP), 광케이블(Optical Fiber), Wi-Fi 신호 변환
  • 물리적인 데이터 전송 (전기 신호, 빛, 전파 사용)

데이터 형태: 비트(Bit) (0과 1)


📌 수신 측 데이터 흐름 (L1 → L7)

수신 측에서는 데이터가 L1(물리 계층) → L7(애플리케이션 계층)으로 올라가면서 복원됨.

  1. L1 (비트 → 프레임): 전기 신호/광신호를 디지털 데이터로 변환
  2. L2 (프레임 → 패킷): 목적지 MAC 주소 확인 후 전달
  3. L3 (패킷 → 세그먼트): IP 주소를 확인하여 최종 목적지로 전달
  4. L4 (세그먼트 → 메시지 조립): TCP/UDP를 사용하여 데이터 복원
  5. L5 (세션 복원): 세션 정보 유지
  6. L6 (데이터 복호화, 압축 해제): TLS 해독, 데이터 복구
  7. L7 (애플리케이션에서 데이터 표시): 웹 페이지 로드, 이메일 표시

🔥 결론

  • L7 → L1 방향(송신): 데이터를 패킷화하여 전송
  • L1 → L7 방향(수신): 데이터를 복원하여 애플리케이션에서 표시
  • L4(TCP/UDP) → 신뢰성 여부 결정 (TCP=신뢰, UDP=빠름)
  • L3(IP) → 목적지 네트워크 경로 설정
  • L2(MAC) → LAN에서 물리적 장비 간 데이터 전달

🚀 즉, OSI 7 계층은 데이터를 작은 단위로 나누어 최적의 경로를 찾아 전송하고, 수신 측에서는 다시 원래 데이터로 복원하는 과정이야!


✅ Mbps란?

📌 Mbps (Megabits per second) 개념

  • **Mbps(Megabits per second)**는 네트워크 속도를 나타내는 단위야.
  • 1Mbps = 1초에 1,000,000비트(1Mb) 전송 가능
  • 1바이트(Byte) = 8비트(Bit)이므로, 1Mbps = 0.125MB/s (메가바이트/초)
  • 인터넷 속도, 네트워크 대역폭(Bandwidth)을 측정할 때 주로 사용됨.

📌 Mbps와 MBps 차이

단위 설명

Mbps (Megabits per second) 네트워크 속도를 나타내는 단위 (1Mbps = 1,000,000bit/s)
MBps (Megabytes per second) 파일 다운로드 속도를 나타낼 때 사용 (1MBps = 8Mbps)

💡 예제

  • 인터넷 속도 100Mbps = 초당 12.5MB(메가바이트) 다운로드 가능
  • 영화 파일 700MB 다운로드 시 100Mbps 속도라면 약 56초 걸림 (700MB ÷ 12.5MB/s)

✅ 단일 라우터 vs. 라우터 이중화

📌 단일 라우터 (Single Router)

  • 하나의 라우터만 사용하여 네트워크를 운영하는 방식
  • 설정이 간단하고 비용이 저렴하지만, 라우터 장애 발생 시 네트워크 전체가 다운됨.
  • 소규모 사무실, 가정에서는 보통 단일 라우터 사용.

💡 단점
❌ 라우터가 고장 나면 네트워크 완전히 마비
❌ 장애 복구가 어려움


📌 라우터 이중화 (Router Redundancy)

  • 두 개 이상의 라우터를 사용하여 네트워크 안정성을 높이는 방식
  • 한 라우터가 고장 나도 백업 라우터가 자동으로 동작 (Failover 지원)
  • 기업, 데이터센터, 고가용성(HA) 네트워크에서 필수적으로 사용됨.

라우터 이중화 방식

  1. Active-Standby (핫스탠바이, Hot Standby)
    • 하나의 라우터(Active)만 동작하고, 나머지(Standby)는 대기
    • 장애 발생 시 Standby 라우터가 Active로 전환
    • 예: HSRP, VRRP
  2. Active-Active (로드 밸런싱)
    • 두 개 이상의 라우터가 동시에 트래픽을 처리
    • 네트워크 부하를 분산하여 성능 최적화
    • 예: GLBP (Gateway Load Balancing Protocol)

이중화 프로토콜

프로토콜 설명

HSRP (Hot Standby Router Protocol) Cisco 전용 이중화 프로토콜
VRRP (Virtual Router Redundancy Protocol) 오픈 표준 기반 이중화 프로토콜
GLBP (Gateway Load Balancing Protocol) Cisco 전용, 라우터 간 부하 분산 가능

💡 장점
✅ 장애 발생 시 자동 복구 (Failover)
✅ 네트워크 가용성 향상
✅ 대기업, 데이터센터에서 필수


✅ Failover란?

📌 Failover 개념

  • **Failover(페일오버)**는 네트워크, 서버, 방화벽, 라우터 등의 장비가 고장났을 때 자동으로 예비 장비(Backup)로 전환하는 기술이야.
  • 장애가 발생하면 즉시 백업 시스템이 활성화되어 서비스가 중단되지 않도록 함.
  • 데이터센터, 기업 네트워크, 클라우드 환경에서 필수적으로 사용됨.

Failover의 핵심 기능

  1. 장애 발생 시 자동 전환
    • 예: 메인 라우터가 다운되면 백업 라우터가 자동으로 동작
  2. 서비스 중단 최소화
    • 예: DB 서버 장애 시 대기 서버로 전환하여 데이터 서비스 유지
  3. 무중단 운영 (High Availability, HA)
    • 예: 방화벽(Firewall) 장애 시 예비 방화벽이 즉시 트래픽 처리

💡 Failover 예제

Failover 방식 설명

라우터 Failover 라우터 장애 시 예비 라우터가 즉시 활성화 (HSRP, VRRP)
방화벽 Failover 방화벽 장애 시 대체 방화벽이 자동으로 네트워크 보호
서버 Failover 서버 장애 시 백업 서버로 자동 전환
스토리지 Failover 스토리지 장애 시 다른 디스크로 전환하여 데이터 보호

📌 정리

개념 설명

Mbps 네트워크 속도 단위 (1Mbps = 1,000,000bit/s)
단일 라우터 하나의 라우터로 네트워크 운영 (장애 시 네트워크 마비)
라우터 이중화 두 개 이상의 라우터로 장애 발생 시 자동 복구
Failover 네트워크 장애 발생 시 예비 장비로 자동 전환

🚀 즉, 네트워크 안정성을 높이려면 반드시 "라우터 이중화"와 "Failover"를 적용해야 함!


✅ 네트워크 케이블 및 광 모듈 정리

네트워크에서 케이블과 광 모듈(SFP, GBIC)은 중요한 역할을 해.
각 케이블의 역할과 특성을 자세히 설명할게.


📌 1. 광케이블(Fiber Optic Cable) vs. UTP 케이블

구분 광케이블(Fiber Optic) UTP 케이블(Unshielded Twisted Pair)

전송 매체 빛(광신호) 전기 신호
속도 최대 400Gbps 이상 최대 10Gbps
거리 최대 100km 이상 최대 100m
노이즈 영향 거의 없음 전자기 간섭(EMI) 영향 받음
사용 환경 데이터센터, 장거리 네트워크(WAN) 사무실, LAN 네트워크

광케이블 특징

  • 데이터 손실 없이 장거리(최대 100km) 전송 가능
  • 전자기 간섭(EMI, RFI) 없음 → 공장, 병원, 데이터센터에서 필수
  • 싱글모드(SM) vs. 멀티모드(MM)로 구분됨

UTP 케이블 특징

  • 짧은 거리(최대 100m)에서 저렴하고 간편하게 설치 가능
  • 랜선(RJ-45 커넥터)로 사용 (사무실, 가정에서 일반적으로 사용)

📌 2. 멀티모드(Multi-Mode) vs. 싱글모드(Single-Mode)

광케이블은 멀티모드(MM)와 싱글모드(SM)로 나뉘며, 각기 다른 용도로 사용돼. - 광케이블만 멀티/싱글모드

 

 

 

                                멀티모드 (MM, Multi-Mode)                                                      싱글모드 (SM, Single-Mode)

전송 방식 여러 개의 광신호(레이저) 전송 하나의 광신호 전송
레이저 종류 LED 기반 (저가) 레이저 기반 (고가)
코어 직경 50~62.5㎛ (굵음) 8~10㎛ (가늘음)
최대 전송 거리 400m~2km 10km~100km 이상
대역폭 상대적으로 낮음 매우 높음
사용 환경 데이터센터, 건물 내 네트워크 장거리(WAN, ISP 네트워크)

멀티모드(MM)

  • 코어가 굵어서 여러 개의 신호(레이저)를 동시에 전송 가능
  • 단거리(최대 2km)에서 주로 사용 (데이터센터, 건물 내 네트워크)
  • 비용이 저렴하지만, 장거리 전송이 어려움

싱글모드(SM)

  • 코어가 매우 가늘어서 한 개의 신호(레이저)를 직진 형태로 전송
  • 장거리(최대 100km 이상) 통신 가능 (WAN, 통신사 네트워크)
  • 속도와 대역폭이 높지만, 광 트랜시버(SFP 모듈) 비용이 비쌈

📌 3. 케이블 색깔에 따른 역할

색깔 유형 사용 모드 역할

노란색 (Yellow) 광케이블 싱글모드(SM) 장거리 네트워크 (10km 이상)
주황색 (Orange) 광케이블 멀티모드(MM, OM1/OM2) 단거리 네트워크 (400m 이내)
아쿠아색 (Aqua) 광케이블 멀티모드(MM, OM3/OM4) 고속 데이터센터 네트워크 (10~40Gbps)
하늘색 (Light Blue) DAC 케이블 SFP+ DAC 스위치 간 고속 연결 (데이터센터)
회색 (Gray) UTP 케이블 CAT5e/CAT6 일반적인 이더넷(1Gbps)
파란색 (Blue) UTP 케이블 CAT6A 고속 이더넷(10Gbps)

💡 색깔로 광케이블 타입을 쉽게 구별 가능!

  • 노란색 = 싱글모드 (장거리)
  • 아쿠아색, 주황색 = 멀티모드 (단거리, 데이터센터)

📌 4. 롱레인지(LR) vs. 쇼트레인지(SR)

광 트랜시버(SFP, GBIC)에는 전송 거리에 따라 **SR(Short Range)과 LR(Long Range)**이 있어.

 

                                                    SR (Short Range)                                 LR (Long Range)

사용 모드 멀티모드(MM) 싱글모드(SM)
전송 거리 최대 400m~2km 최대 10km~100km
파장 (nm) 850nm 1310nm, 1550nm
사용 환경 데이터센터, 건물 내부 장거리 WAN, ISP 네트워크

SR (Short Range)

  • 멀티모드(MM) 광케이블 사용
  • 단거리(400m~2km) 네트워크 구축
  • 주로 데이터센터, 건물 내부 네트워크에 사용됨

LR (Long Range)

  • 싱글모드(SM) 광케이블 사용
  • 장거리(10km~100km) 네트워크 구축
  • 주로 ISP, 광역 네트워크(WAN), 통신사 인프라에서 사용됨

💡 쉽게 말하면?

  • SR은 데이터센터(짧은 거리), LR은 통신사(WAN, 장거리)에서 사용!

✅ GBIC과 SFP란?

네트워크 장비(스위치, 라우터 등)에서 광케이블을 직접 연결할 수 없고,
별도의 **광 모듈(Transceiver, 트랜시버)**을 장착해야 해.
이 역할을 하는 대표적인 모듈이 바로 GBIC과 SFP야.

💡 쉽게 말하면?
👉 GBIC과 SFP는 네트워크 장비에 광케이블을 연결할 수 있도록 변환해주는 장치!


📌 1. GBIC과 SFP의 역할

📌 왜 GBIC과 SFP가 필요할까?

  • 네트워크 스위치, 라우터는 기본적으로 RJ-45(UTP) 포트만 지원하는 경우가 많음.
  • 하지만 장거리 네트워크에서는 광케이블(Fiber Optic)을 사용해야 함.
  • 따라서 광신호 ↔ 전기신호 변환이 필요함 → 이 역할을 하는 것이 GBIC과 SFP!

GBIC과 SFP가 하는 일

  1. 네트워크 장비(스위치, 라우터)와 광케이블 연결
  2. 전기 신호(네트워크 장비) ↔ 광 신호(광케이블) 변환
  3. 장거리 네트워크(10km~100km) 전송 가능
  4. 모듈 교체로 다양한 속도(1Gbps, 10Gbps, 40Gbps 등) 지원 가능

📌 2. GBIC vs. SFP 차이점

                        GBIC (Gigabit Interface Converter)                     SFP (Small Form-factor Pluggable)

크기 큼 (구형, 2배 크기) 작음 (신형, 더 컴팩트)
속도 최대 1Gbps 최대 10Gbps (SFP+), 40~100Gbps (QSFP)
사용 장비 구형 네트워크 장비에서 사용 최신 네트워크 장비에서 사용
소켓 타입 크기가 커서 포트가 적음 작아서 여러 개 장착 가능
대체 가능 여부 SFP로 대체 가능 GBIC보다 효율적, 최신 장비에서 사용

💡 쉽게 말하면?

  • GBIC(구형, 크기 큼, 최대 1Gbps) → 과거 장비에서 사용됨.
  • SFP(신형, 크기 작음, 최대 10Gbps 이상) → 최신 네트워크에서 주로 사용됨.

📌 3. GBIC/SFP 동작 방식

💡 1) 네트워크 장비에 직접 연결

  • 스위치 또는 라우터의 GBIC/SFP 포트에 트랜시버(GBIC 또는 SFP)를 장착함.
  • 트랜시버에 광케이블을 연결하여 네트워크를 확장함.

연결 흐름 📌 [스위치] —[SFP 트랜시버]—[광케이블]—[SFP 트랜시버]—[다른 스위치]
👉 즉, 광케이블을 직접 장착할 수 없는 네트워크 장비에서 "중간 변환기" 역할을 함!


💡 2) 신호 변환 과정

  1. 전기 신호 입력 (스위치, 라우터에서 데이터 전송)
  2. SFP/GBIC에서 전기 신호 → 광 신호로 변환
  3. 광케이블을 통해 데이터 전송 (멀티모드/싱글모드)
  4. 목적지 네트워크 장비(SFP/GBIC)에서 다시 광 신호 → 전기 신호 변환
  5. 최종적으로 데이터 수신 장비(스위치, 라우터)에서 처리됨

💡 즉, SFP/GBIC는 광신호와 전기신호를 변환하는 "중간 브릿지" 역할을 함!


📌 4. SFP의 확장 버전 (SFP+ & QSFP)

기존 SFP보다 더 빠른 속도와 확장성이 필요한 경우, 발전된 버전이 있어.

모듈 유형 속도 설명

SFP (Small Form-factor Pluggable) 1Gbps 일반적인 기가비트 광 모듈
SFP+ (Enhanced SFP) 10Gbps 데이터센터, 서버 네트워크
QSFP (Quad SFP) 40Gbps 대형 데이터센터, 클라우드 환경
QSFP+ (Enhanced QSFP) 100Gbps 초고속 네트워크

💡 즉, 네트워크 속도가 증가함에 따라 SFP도 계속 발전하고 있음!


📌 5. GBIC/SFP 선택 가이드

📌 네트워크 환경에 따라 적절한 GBIC/SFP를 선택해야 해.

환경 추천 트랜시버 추천 광케이블

건물 내부 네트워크 (단거리) SFP SR (Short Range, 1~10Gbps) 멀티모드 (주황색, 아쿠아색)
데이터센터 연결 (중거리) SFP+ LR (10Gbps 이상) 싱글모드 (노란색)
ISP, WAN (장거리) QSFP+ (40Gbps 이상) 싱글모드 (노란색)
구형 장비 사용 GBIC (1Gbps 이하) 멀티모드 또는 싱글모드

 

 


🔥 결론

1️⃣ 광케이블은 UTP보다 속도 빠르고 장거리 전송 가능 (싱글모드=장거리, 멀티모드=단거리)
2️⃣ 아쿠아색(멀티모드, 데이터센터), 노란색(싱글모드, 장거리)
3️⃣ LR(장거리, WAN), SR(단거리, 데이터센터)
4️⃣ GBIC(구형) vs. SFP(최신, 소형, 고속)

🚀 즉, 광케이블과 SFP 모듈을 선택할 때 거리, 속도, 네트워크 환경을 고려해야 함!

✅ 방화벽(Firewall)이란?

방화벽(Firewall)은 네트워크에서 들어오고 나가는 트래픽을 필터링하여 보안을 유지하는 장치 또는 소프트웨어야.
쉽게 말하면 "네트워크의 문지기" 역할을 하는 거지.


📌 방화벽의 기본 개념

💡 왜 방화벽이 필요할까?

  • 네트워크를 보호하지 않으면 해커, 악성코드, 불법 접근 등의 위협에 노출될 수 있어.
  • 방화벽이 없으면 모든 외부 트래픽이 내부 네트워크로 바로 들어올 수 있음.
  • 방화벽을 사용하면 허용된 트래픽만 통과시키고, 불법 트래픽은 차단할 수 있음.

방화벽의 역할

  • 허가된 트래픽만 통과시키고, 불필요하거나 위험한 트래픽을 차단
  • 내부 네트워크 보호 (Private Network vs. Public Network 구분)
  • IP, 포트, 프로토콜 기반으로 접근 제어(ACL, Rule 설정)

🚀 즉, 방화벽은 "네트워크 보안의 1차 방어선"이야!


📌 방화벽의 작동 원리

방화벽은 트래픽을 필터링하는 규칙(Rules)을 기반으로 동작해.
트래픽이 방화벽을 통과할 때, 방화벽이 "이 트래픽을 허용할지 차단할지" 판단하는 거지.

기본적인 방화벽 동작 방식

  1. 클라이언트가 서버(예: www.google.com)로 요청을 보냄.
  2. 요청이 방화벽을 통과하면서, 방화벽이 IP, 포트, 프로토콜을 검사.
  3. 방화벽이 사전에 설정된 허용(Allow) / 차단(Deny) 규칙과 비교.
  4. 허용된 트래픽만 목적지로 전송하고, 차단된 트래픽은 폐기(Drop) 또는 거부(Reject).

방화벽에서 필터링할 수 있는 요소

  • IP 주소: 특정 IP에서 들어오는 요청 차단 (예: 192.168.1.1 차단)
  • 포트 번호: 특정 포트만 허용 (예: HTTP(80), HTTPS(443) 허용)
  • 프로토콜: TCP, UDP, ICMP 등 특정 프로토콜만 허용 또는 차단
  • 패킷 내용 검사: 고급 방화벽(WAF 등)은 트래픽 내용까지 검사하여 차단 가능

📌 방화벽의 종류

방화벽은 크게 소프트웨어 방화벽과 하드웨어 방화벽으로 나뉘고, 동작 방식에 따라 패킷 필터링, 상태 저장형, 애플리케이션 계층 방화벽으로 구분돼.

✅ 1. 유형별 방화벽

방화벽 유형 설명 예시

소프트웨어 방화벽 OS에서 실행되는 방화벽 Windows Firewall, iptables(Linux)
하드웨어 방화벽 별도의 네트워크 장비로 운영 Cisco ASA, Palo Alto, Fortinet
클라우드 방화벽 클라우드 환경에서 운영 AWS WAF, Azure Firewall

소프트웨어 방화벽 → 개인 PC, 서버에서 작동 (OS 내장)
하드웨어 방화벽 → 기업, 데이터센터에서 사용 (강력한 보안)
클라우드 방화벽 → 클라우드 환경에서 가상 방화벽 제공


✅ 2. 동작 방식에 따른 방화벽 종류

방화벽 종류 설명 예시

패킷 필터링 방화벽 IP, 포트 기반으로 단순 허용/차단 Cisco ACL, iptables
상태 저장형 방화벽 (Stateful Firewall) 기존 연결 정보 추적 가능 Cisco ASA, Palo Alto
프록시 방화벽 애플리케이션 계층에서 트래픽 검사 Squid Proxy, Blue Coat
차세대 방화벽(NGFW, Next-Gen Firewall) DPI(Deep Packet Inspection) 등 고급 기능 지원 Palo Alto NGFW, Fortinet

패킷 필터링 방화벽 → 가장 기본적인 방식, 단순 허용/차단
상태 저장형 방화벽 → 세션 정보까지 확인하여 보안 강화
프록시 방화벽 → 트래픽을 중간에서 검사 후 전달 (보안 강화)
차세대 방화벽(NGFW)DPI(Deep Packet Inspection), IPS/IDS 기능 포함


📌 방화벽 룰 설정 예시 (ACL)

방화벽은 "규칙(Rule)"을 설정해서 작동함.

✅ 예제 1: SSH(22번 포트) 차단

iptables -A INPUT -p tcp --dport 22 -j DROP

✅ 예제 2: HTTP(80), HTTPS(443) 트래픽만 허용

iptables -A INPUT -p tcp --match multiport --dports 80,443 -j ACCEPT

✅ 예제 3: 특정 IP(192.168.1.100) 차단

iptables -A INPUT -s 192.168.1.100 -j DROP

💡 이렇게 방화벽은 "허용/차단 규칙"을 설정해서 트래픽을 관리해.
💡 대기업에서는 GUI 기반 방화벽(Cisco ASA, Palo Alto)에서 룰을 설정함.


📌 방화벽과 NAT, IDS/IPS 비교

기능 방화벽 (Firewall) NAT (Network Address Translation) IDS/IPS

목적 보안 (허용/차단) 사설 IP ↔ 공인 IP 변환 침입 탐지 및 방어
트래픽 제어 ✅ 있음 ❌ 없음 ✅ 있음 (IPS)
공격 차단 ✅ 가능 ❌ 불가능 ✅ 가능 (IPS)
동작 방식 ACL, Stateful Inspection IP 변환 패킷 분석 (Signature 기반)

🚀 방화벽 = "보안 관문" (허용/차단)
🚀 NAT = "IP 변환" (내부/외부 네트워크 연결)
🚀 IDS/IPS = "침입 탐지 및 차단" (악성 트래픽 감지)


🔥 결론

  • 방화벽(Firewall)은 네트워크에서 허용된 트래픽만 통과시키고, 불법 트래픽을 차단하는 장비.
  • ACL, Stateful Inspection, DPI(Deep Packet Inspection) 방식으로 보안을 강화할 수 있음.
  • 하드웨어 방화벽(기업용)과 소프트웨어 방화벽(개인/서버용)으로 구분됨.
  • 차세대 방화벽(NGFW)은 IDS/IPS 기능까지 포함하여 강력한 보안 제공.


✅ ISP(Internet Service Provider)란?

ISP(인터넷 서비스 제공업체, Internet Service Provider)는 사용자가 인터넷에 연결할 수 있도록 네트워크 서비스를 제공하는 회사야.

쉽게 말하면, 인터넷을 사용할 수 있도록 연결해주는 회사를 말해.
우리가 집에서 Wi-Fi를 쓰거나, 회사에서 인터넷을 사용할 때 ISP를 통해 인터넷과 연결되는 것이야.


📌 ISP의 주요 역할

1. 인터넷 연결 제공

  • 가정용, 기업용 인터넷 서비스 제공 (예: 광랜, 5G, 위성 인터넷)
  • 공인 IP 주소 제공 (인터넷과 연결되는 네트워크 주소)

2. 네트워크 인프라 운영

  • 백본 네트워크 운영 (대형 인터넷 트래픽 처리)
  • 데이터센터, 해저 케이블, 위성 네트워크 관리

3. 트래픽 관리 및 보안 제공

  • DDoS 방어, 방화벽, 콘텐츠 필터링 제공
  • 특정 웹사이트 차단 가능 (국가별 인터넷 검열)

4. 추가 서비스 제공

  • 클라우드 서비스, 웹 호스팅, VoIP(인터넷 전화), IPTV(인터넷 TV)

📌 ISP의 종류

ISP는 제공하는 서비스와 규모에 따라 여러 단계로 나뉘어.

ISP 유형 설명 예제

Tier 1 ISP 글로벌 백본 네트워크 운영 (인터넷 망 제공) AT&T, NTT, Lumen (Level 3)
Tier 2 ISP Tier 1 ISP와 연결하여 인터넷 제공 KT, SK Broadband, LG U+
Tier 3 ISP 일반 사용자에게 인터넷 서비스 제공 지역 인터넷 제공업체, 스타링크(위성)

💡 쉽게 말하면?

  • Tier 1 ISP → 세계적인 인터넷 인프라 운영 (대형 백본 네트워크)
  • Tier 2 ISP → 국가 또는 지역 단위로 인터넷 제공
  • Tier 3 ISP → 일반 가정, 회사에 인터넷을 제공하는 최종 업체

📌 ISP가 제공하는 인터넷 유형

인터넷 유형 설명 속도

광케이블 (Fiber Optic) 가장 빠른 인터넷 (FTTH) 최대 10Gbps
케이블 인터넷 (Cable, HFC) 기존 TV 케이블망 이용 100Mbps ~ 1Gbps
DSL (Digital Subscriber Line) 전화선 기반 인터넷 10Mbps ~ 100Mbps
5G/LTE (무선 인터넷) 이동통신망 기반 인터넷 최대 10Gbps (5G)
위성 인터넷 (Satellite) 위성을 통해 인터넷 연결 100Mbps (스타링크)

💡 광케이블이 가장 빠르고 안정적이지만, 지역에 따라 DSL, 위성 인터넷을 사용해야 할 수도 있음.


📌 ISP의 주요 네트워크 구성

ISP는 다양한 네트워크 장비를 사용해서 인터넷을 제공해.

1. 백본 네트워크 (Backbone Network)

  • ISP의 주요 네트워크 인프라 (Tier 1 ISP에서 운영)
  • 초고속 광케이블, 해저 케이블, 위성망을 포함

2. 라우터 (Router)

  • 인터넷 트래픽을 최적의 경로로 전달
  • BGP(Border Gateway Protocol)로 ISP 간 데이터 교환

3. DNS 서버 (Domain Name System)

  • IP 주소 ↔ 도메인 변환 (예: google.com → 142.250.185.78)

4. 방화벽 & 보안 시스템

  • DDoS 공격 방어, 악성 트래픽 차단

5. 캐시 서버 (CDN, Content Delivery Network)

  • 유튜브, 넷플릭스 같은 콘텐츠를 빠르게 제공하기 위해 ISP 내부에 캐시 저장

📌 ISP와 관련된 네트워크 개념

개념 설명

BGP (Border Gateway Protocol) ISP 간 인터넷 경로 설정 프로토콜
NAT (Network Address Translation) 공인 IP ↔ 사설 IP 변환
QoS (Quality of Service) 네트워크 트래픽 우선순위 설정 (속도 조절)
CDN (Content Delivery Network) 넷플릭스, 유튜브 같은 콘텐츠를 ISP 내부 캐싱
Peering (피어링) ISP 간 무료 데이터 교환 (Tier 1 ↔ Tier 2)

💡 즉, ISP는 단순히 인터넷을 연결해주는 것이 아니라, 네트워크 경로 최적화, 보안, 트래픽 관리까지 수행하는 역할을 해.


🔥 결론

  • ISP(인터넷 서비스 제공업체) = 인터넷을 연결해주는 회사
  • Tier 1 → Tier 3 ISP 계층 구조로 인터넷 서비스 제공
  • 광케이블, DSL, 5G, 위성 인터넷 등 다양한 연결 방식 존재
  • BGP, NAT, DNS, QoS 같은 네트워크 기술을 사용하여 트래픽 관리

✅ 라우터, 스위치, 게이트웨이: 네트워크 핵심 장비 개념

네트워크에서 라우터(Router), 스위치(Switch), 게이트웨이(Gateway)는 각기 다른 역할을 하지만, 모두 데이터 통신을 관리하는 핵심 장비야.

📌 기본 개념 요약

  • 라우터네트워크 간(IP 기반) 데이터 전달
  • 스위치같은 네트워크(LAN) 내부에서 데이터 전달 (MAC 기반)
  • 게이트웨이서로 다른 네트워크/프로토콜을 변환하여 연결

📌 1. 라우터(Router)란?

라우터는 네트워크 간 패킷을 전달하고 최적의 경로를 결정하는 장비.
네트워크 계층(L3, Network Layer)에서 동작하며, IP 주소를 기반으로 패킷을 전달해.

라우터의 역할

  1. 네트워크 간 연결 (LAN ↔ WAN, WAN ↔ WAN)
    • 회사 네트워크(사설망)와 인터넷(공용망)을 연결
  2. 패킷 라우팅 (IP 주소 기반)
    • 목적지 IP 주소를 확인하여 최적의 경로로 패킷 전달
  3. NAT(Network Address Translation) 지원
    • 내부 사설 IP ↔ 공인 IP 변환 (인터넷 통신 가능하게 함)
  4. 라우팅 프로토콜 운영
    • Static Routing (고정 경로 설정)
    • Dynamic Routing (라우팅 프로토콜: OSPF, BGP, EIGRP 등)

라우터의 핵심 기능

기능 설명

IP 패킷 포워딩 목적지 IP 주소를 기반으로 패킷 전달
라우팅 테이블 유지 네트워크 경로 정보를 저장하고 최적의 경로 선택
NAT (IP 변환) 사설 IP ↔ 공인 IP 변환
ACL (Access Control List) 특정 IP/포트 접근 제한 (기본적인 방화벽 기능)

라우팅 프로토콜

라우팅 유형 프로토콜 설명

Distance Vector RIP, EIGRP 홉 수 기반 경로 선택
Link-State OSPF, IS-IS 네트워크 토폴로지를 기준으로 경로 최적화
Path-Vector BGP ISP 간 경로 최적화 (인터넷 백본)

💡 라우터는 네트워크 경계를 구분하고, 트래픽을 최적의 경로로 전달하는 역할을 함!


📌 2. 스위치(Switch)란?

스위치는 같은 네트워크(LAN) 내부에서 패킷을 전달하는 장비.
데이터 링크 계층(L2, Data Link Layer)에서 동작하며, MAC 주소 기반으로 데이터 프레임을 전달해.

스위치의 역할

  1. LAN(Local Area Network) 구성
    • 회사 내부, 데이터센터, 사무실 네트워크 구축
  2. 프레임 포워딩 (MAC 주소 기반)
    • 패킷이 목적지 MAC 주소를 기반으로 전송됨
  3. VLAN(Virtual LAN) 지원
    • 네트워크 논리적 분리 (한 개의 스위치에서 여러 개의 네트워크 구성 가능)
  4. 브로드캐스트 도메인 최소화
    • 스위치 포트마다 별도의 Collision Domain을 가짐 (허브보다 성능 우수)

스위치의 핵심 기능

기능 설명

MAC 주소 기반 데이터 전달 목적지 MAC 주소를 확인하여 적절한 포트로 전송
MAC 주소 테이블 유지 네트워크 장비들의 MAC 주소와 연결된 포트 정보 저장
VLAN 지원 논리적으로 네트워크를 분리하여 보안 및 트래픽 관리
STP (Spanning Tree Protocol) 루프 방지 (네트워크 장애 예방)

스위치 종류

스위치 유형 설명

Unmanaged Switch 설정 없이 단순히 네트워크 연결만 제공
Managed Switch VLAN, QoS, SNMP 등 관리 기능 제공
L2 Switch MAC 주소 기반 데이터 전달 (기본적인 스위치)
L3 Switch IP 기반 라우팅 기능 포함 (라우팅 기능 지원)

💡 스위치는 네트워크 내부에서 데이터 트래픽을 효율적으로 전달하는 역할을 함!


📌 3. 게이트웨이(Gateway)란?

게이트웨이는 서로 다른 네트워크, 프로토콜을 변환하여 연결하는 장비.
일반적으로 L3 계층 이상(L4~L7)에서 동작하며, 데이터 변환 기능을 수행해.

게이트웨이의 역할

  1. 네트워크 간 통신 브릿지 역할
    • 서로 다른 프로토콜을 사용하는 네트워크 간 통신 연결
    • 예) IPv4 ↔ IPv6 변환, TCP ↔ UDP 변환
  2. 방화벽 역할 가능
    • 패킷 필터링, IPSec VPN 터널링
  3. VoIP 게이트웨이
    • 음성(아날로그) ↔ IP 패킷 변환

게이트웨이의 핵심 기능

기능 설명

프로토콜 변환 서로 다른 네트워크 프로토콜 변환 (IPv4 ↔ IPv6)
VoIP 지원 아날로그 전화 ↔ IP 기반 VoIP 변환
VPN 터널링 원격 네트워크 보안 연결 지원
방화벽 기능 포함 가능 패킷 필터링, 접근 제어

게이트웨이 예제

  • ISP 라우터 → 인터넷 연결을 위한 기본 게이트웨이
  • VoIP 게이트웨이 → 기존 전화망을 인터넷 전화(VoIP)로 변환
  • 클라우드 게이트웨이 → AWS API Gateway, Azure VPN Gateway

💡 게이트웨이는 네트워크 간 변환을 담당하는 역할!


📌 라우터, 스위치, 게이트웨이 비교 정리

구분 라우터(Router) 스위치(Switch) 게이트웨이(Gateway)

역할 네트워크 간 연결 네트워크 내부 연결 서로 다른 네트워크 변환
기본 단위 IP 주소 기반 라우팅 MAC 주소 기반 데이터 전달 프로토콜 변환
사용 계층 L3 (네트워크 계층) L2 (데이터 링크 계층) L3~L7 (다양한 계층)
주요 기능 패킷 포워딩, NAT, ACL MAC 기반 스위칭, VLAN 프로토콜 변환, 방화벽 기능 가능
사용 환경 인터넷 연결, 기업 네트워크 사무실 LAN, 데이터센터 클라우드, VoIP, VPN

🔥 결론

  1. 라우터 → IP 주소 기반 네트워크 간 데이터 전달 (인터넷 연결, WAN 라우팅)
  2. 스위치 → MAC 주소 기반 LAN 내부 데이터 전달 (사무실 네트워크, VLAN)
  3. 게이트웨이 → 서로 다른 네트워크(프로토콜) 변환 (IPv4 ↔ IPv6, VoIP, VPN)

🚀 즉, 라우터는 "네트워크 간 길 안내", 스위치는 "네트워크 내부 트래픽 관리", 게이트웨이는 "서로 다른 네트워크 연결" 역할을 함!

문제 :

이 문제를 보고 BFS인지 떠올릴 수 있는 요소들 :

1. 최단 변환 과정 찾기: 문제에서 요구하는 것은 ‘가장 짧은 변환 과정’을 찾는 것이다. BFS는 레벨별로 모든 가능성을 탐색하며, 이 과정에서 각 단계의 모든 가능한 경우를 고려하기 때문에 최단 경로를 보장한다.

2. 한 번에 한 글자만 바꿀 수 있는 규칙: 이 규칙은 각 단계에서 가능한 모든 변환을 시도해볼 수 있게 하며, BFS는 이러한 시도를 체계적으로 관리하여 가장 빠른 결과를 도출할 수 있게 한다.

3. words 리스트의 제한된 크기: BFS는 상대적으로 제한된 범위 내에서 효과적으로 작동한다. words의 크기가 50개 이하로 제한되어 있어, BFS를 사용할 경우 너무 많은 메모리를 소모하거나 시간이 과도하게 걸리는 문제를 피할 수 있다.

 

BFS는 큐, DFS는 스택, 재귀를 기반으로 동작한다. 아래 코드를 살펴보자.

from collections import deque

def solution(begin, target, words):
    if target not in words:
        return 0
    queue = deque()
    queue.append((begin, 0))
    visited = set()
    
    while queue:
        curr, steps = queue.popleft()
        if curr == target:
            return steps
        for word in words:
            if word not in visited and sum([c1 != c2 for c1, c2 in zip(curr, word)]) == 1:
                visited.add(word)
                queue.append((word, steps + 1))
    return 0

 

우선, 타겟이 words배열에 없으면 아예 검사 자체를 할 필요가 없으므로 맨 앞단에 이 조건문을 넣어 이 조건이 fail하면 곧바로 끝내도록 한다.

 

다음으로, BFS에서 사용될 큐를 만들어준다. 다음으로, 처음 검사될 단어 begin과 변환 횟수 0 을 튜플에 담아 큐에 넣어준다. 다음으로, 이미 방문한 노드(word)를 재방문 하지 않기 위한 visited를 만든다. 또한, BFS에서는 이 visited가 최단 경로를 보장 해준다. 

 

만약, 타겟 단어가 words배열 안에 존재한다면, while문으로 넘어간다.

 

while queue: 큐에 요소가 하나라도 있는동안,

 

큐에서 요소를 하나 꺼내어 현재 단어(curr), 몇 단계를 거쳐 단어가 변환 되었는지를 나타내는 steps 변수에 할당한다. 만약, 꺼낸 단어가 타겟과 같다면 바로 스텝을 리턴한다. 

 

아니라면, words의 단어들을 하나씩 순회하며 이 단어가 '방문된 적이 없고', 문제의 핵심 조건중 하나인 "단 한가지 단어만 바꿀 수 있다면"을 검사해야 한다. 두개의 단어가 철자 하나만 빼고 모두 같은지 가장 쉽고 빠르게 확인하는 방법은 문자열에 zip을 사용하는것이다. 저 짧은 if문 안에 3개의 스킬(?)이 들어갔다.

 

1. 리스트 컴프리헨션

2. 문자열 zip

3. True == 1, False == 0

 

우선, 

sum([c1 != c2 for c1, c2 in zip(curr, word)])

 

zip 함수를 문자열에 사용하여 두 문자열 간의 다른 문자를 찾는 방법은 매우 유용하다. 이를 통해 한 단어에서 다른 단어로의 변환이 한 글자만 다른지 쉽게 확인할 수 있다.

 

문자열에서의 zip 활용 예

 

curr = "hit", word = "hot"의 예를 들면, zip("hit", "hot")은 각 문자를 인덱스 별로 묶어서 [(h, h), (i, o), (t, t)]과 같은 튜플의 리스트를 생성한다. 이 튜플에서 첫 번째 요소는 c1, 두 번째 요소는 c2로 할당된다.

 

문자 비교와 리스트 컴프리헨션

 

리스트 컴프리헨션 c1 != c2는 각 튜플을 비교하여, 두 문자가 다르면 True, 같으면 False를 반환한다. 따라서 위 예에서는 [False, True, False] 리스트가 생성된다. 이 리스트는 각 문자 위치에서 문자가 같은지 다른지를 나타낸다.

 

True와 False의 수치 계산

 

파이썬에서는 True와 False를 각각 1과 0으로 처리할 수 있다. 이 특성 덕분에 sum([False, True, False]) 호출이 가능하며, 이는 1을 반환한다. 이는 “hit”와 “hot” 사이에 정확히 한 글자만 다름을 의미한다.

 

BFS에서의 활용

 

이 기능을 BFS 탐색에 적용할 때, 큐에서 현재 단어를 꺼내고 이와 한 글자만 다른 모든 단어를 찾아내는 과정에서 중요하게 사용된다. 만약 해당 단어가 방문하지 않은 단어이고 한 개의 문자만 다르다면, 이 단어는 방문 대상으로 간주되어 방문 기록에 추가되고, 큐에는 이 단어와 현재 단계 수에서 1을 더한 값이 함께 저장된다.

 

이러한 절차를 통해 BFS는 각 단계마다 가능한 모든 경로를 탐색하며, 최초로 목표 단어에 도달할 때 그 경로가 최단 경로임을 보장한다. 각 단어는 처음 방문될 때 가장 적은 수의 변환을 거쳐 도달했으므로, 이후에 같은 단어에 도달하는 다른 경로는 더 많은 변환을 필요로 하여 고려되지 않는다.

 

어제 최대힙을 잠깐 공부했었는데, 오늘 공부를 하다가 또 최대힙을 발견하여 최대힙을 다시 정리하면서 넘어가고자 한다.

 

우선, 문제를 보자.

 

문제를 보면, 작업량과 남은 시간을 가지고 최소한의 야근 피로도를 계산하는 문제이다. 여기서 야근 피로도는 남은 작업 시간들의 제곱으로 구해지기 때문에, 남은 시간 n 동안 가능한 한 큰 작업을 최대한 줄여서 피로도를 최소화하는 게 목표이다.

 

예를 들어, 주어진 작업량이 [4, 3, 3]이고 남은 시간이 4라고 하면 이 경우, 가장 큰 값인 4를 먼저 줄이는 게 효율적이다. 그래서 4를 1만큼 줄이면 남은 시간은 3이 되고, 배열은 [3, 3, 3]이 된다. 이후에도 계속 최댓값을 찾아서 1씩 줄여주는 과정을 반복한다. 예를 들어, 3을 또 줄이면 배열은 [3, 3, 2]가 되고 남은 시간은 2가 되는 식으로 진행한다.

 

여기서 문제가 발생하는데:

 

1. 매 반복마다 최댓값을 찾아야 하는데, max() 함수를 반복적으로 호출하면 성능이 떨어진다.

2. max()를 피하기 위해 정렬된 배열을 사용하려고 해도, 매번 배열을 다시 정렬해야 해서 이 방법도 비효율적이다.

 

따라서 최댓값을 빠르게 찾아내면서도 효율적으로 값을 줄일 수 있는 방법을 고려해야 해.

 

이때, 최대, 또는 최소값을 빠르게 찾아내면서 계속 트래킹 할 수 있는 자료구조는 파이썬의 heap 이 있다.

 

힙(Heap)은 완전 이진 트리(Complete Binary Tree) 구조를 가지는 특수한 트리 기반의 자료구조로, 최댓값 또는 최솟값을 빠르게 찾아내기 위한 구조다. 힙은 크게 최소 힙최대 힙으로 나뉘며, 각각 특정 조건을 만족하는 이진 트리 형태로 값을 저장한다.

 

1. 최소 힙(Min Heap):

부모 노드가 자식 노드보다 작거나 같은 값을 가진다.

즉, 루트(root) 노드는 항상 힙에서 가장 작은 값이다.

이를 통해 매번 가장 작은 값을 빠르게 꺼낼 수 있다.

예를 들어, [1, 3, 5, 7, 9]가 최소 힙으로 구성되어 있다면, 1이 최솟값으로 가장 위에 자리잡는다.

2. 최대 힙(Max Heap):

부모 노드가 자식 노드보다 크거나 같은 값을 가진다.

즉, 루트 노드는 항상 힙에서 가장 큰 값이다.

이를 통해 매번 가장 큰 값을 빠르게 꺼낼 수 있다.

예를 들어, [9, 7, 5, 3, 1]이 최대 힙으로 구성되어 있다면, 9가 최댓값으로 가장 위에 자리잡는다.

 

힙의 핵심 특징:

 

시간 복잡도: 삽입(insert)과 삭제(remove)는 O(log N)의 시간 복잡도를 가진다. 이는 트리의 높이에 해당하는 연산이기 때문이다. 힙은 트리가 완전히 채워지므로, 트리의 높이는 log N에 비례한다.

실시간 트래킹: 반복적으로 최댓값 또는 최솟값을 요구하는 문제에서 매우 유용하다. 힙은 트리 구조를 유지하며 값을 삽입하거나 삭제하므로 매번 정렬할 필요 없이 효율적으로 최댓값이나 최솟값을 찾을 수 있다.

 

파이썬에서의 힙 구현:

 

파이썬의 heapq 모듈은 기본적으로 최소 힙을 제공한다. 즉, 이 모듈을 사용하면 항상 최솟값을 빠르게 찾을 수 있다.

최대 힙은 별도로 제공되지 않으나, 음수 변환을 통해 간단히 구현할 수 있다. 값을 삽입할 때 음수로 변환하고, 값을 꺼낼 때 다시 양수로 변환하여 최대 힙처럼 동작하게 할 수 있다.

 

heapq 모듈 주요 함수:

1. heapq.heappush(heap, item): item을 힙에 추가한다.

2. heapq.heappop(heap): 힙에서 최솟값을 꺼낸다.

3. heapq.heapify(list): 주어진 리스트를 힙 구조로 변환한다.

 

최대 힙 예시 (파이썬에서 음수 변환을 통해 구현):

import heapq

# 최대 힙을 구현하기 위해 값의 부호를 반전

max_heap = []

heapq.heappush(max_heap, -10)  # 10을 최대 힙에 추가 (음수로)

heapq.heappush(max_heap, -30)  # 30을 최대 힙에 추가 (음수로)

heapq.heappush(max_heap, -20)  # 20을 최대 힙에 추가 (음수로)

# 최대값 꺼내기

print(-heapq.heappop(max_heap))  # 출력: 30 (음수로 저장했기 때문에 다시 양수로 바꿈)

 

힙의 용도:

우선순위 큐 구현: 항상 우선순위가 높은 작업을 먼저 처리해야 하는 경우.

정렬이 필요 없는 트래킹: 최댓값이나 최솟값을 자주 구하는 문제에서 매우 효율적.

작업 스케줄링: 작업 시간을 기준으로 우선순위를 정해 빠르게 처리를 해야 하는 스케줄링 문제에서 사용.

 

힙은 정렬이 반복적으로 필요할 때 매우 효율적이며, 특히 우선순위가 중요한 문제에서 자주 사용되는 자료구조이다.

 

그러면, 이 문제에 힙을 구현해 보자. 이 문제는, 최솟값이 아니라 최댓값을 실시간으로 트래킹 해야 하므로 최대힙을 사용해야 한다.

import heapq

def solution(n, works):
    res = 0
    works = [-x for x in works]
    heapq.heapify(works)
    
    while n > 0 and works[0] < 0:
        max_val = -heapq.heappop(works)
        max_val -= 1
        n -= 1
        heapq.heappush(works, -max_val)
    
    for i in works:
        res += pow(i, 2)
    return res

 

우선, import heapq를 사용해 힙을 가져온다.

 

그리고 최대힙을 구현하기 위해 주어진 works 배열의 각 요소를 음수로 변환한다. 이는 파이썬의 기본 힙이 최소 힙이기 때문에, 음수로 변환하여 최소 힙을 최대 힙처럼 사용할 수 있기 때문이다. 이후, heapq.heapify(works)를 사용해 음수로 변환한 works 배열을 힙 자료구조로 변환한다.

 

이제, while문에서:

 

먼저, heapq.heappop(works)를 사용해 works 힙에서 최댓값을 꺼낸다. 음수로 변환했기 때문에 음수 중 가장 작은 값이 나오지만, 우리는 이를 다시 양수로 바꿔 원래의 최댓값을 구한다.

 

다음으로, 꺼낸 최댓값을 1 감소시키고, 이를 다시 힙에 넣어야 한다. 이때, 다시 음수로 변환하여 넣어야 최대힙을 유지할 수 있으므로, heapq.heappush(works, -max_val)을 사용해 힙에 삽입한다.

 

이 과정을 반복하면, 매 반복마다 최대값이 유지되는 힙 구조를 통해 효율적으로 최댓값을 줄여 나갈 수 있다. 이 방식은 max()sort()를 반복해서 호출할 필요 없이 최댓값을 바로 꺼내고 수정한 뒤 다시 넣는 작업을 효율적으로 처리할 수 있다.

 

따라서, 최대값을 계속 유지하면서 실시간으로 값을 조정할 수 있는 장점을 이용하는 것이다.

 

 

'CodingTest > 프로그래머스' 카테고리의 다른 글

BFS - 단어 변환  (0) 2024.10.18
완전탐색 - Itertools  (0) 2024.10.18
[프로그래머스] 타겟 넘버  (0) 2024.08.05
[프로그래머스]게임 맵 최단거리  (0) 2024.08.05
[프로그래머스] 할인 행사  (0) 2024.08.03

프로그래머스를 풀다가 완전 탐색 문제를 만났다.

 

위 문제는 결국 모든 조합을 찾아 소수가 되는 경우를 찾아야 한다. 전형적인 완전 탐색 문제이다. 

 

하지만 문제가 하나 더 있다. 여기서 어떻게 모든 조합을 찾아낼 수 있을까? for문을 사용해 모든 조합을 만들면 너무 코드가 복잡해진다. 이럴땐 Python의 itertools.combinations을 사용하여 간편하게 3개의 숫자를 고를 수 있다.

 

import itertools
import math

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            return False
    return True

def solution(nums):
    count = 0
    # 3개의 숫자를 선택하는 모든 조합 구하기
    for comb in itertools.combinations(nums, 3):
        if is_prime(sum(comb)):  # 선택한 숫자들의 합이 소수인지 확인
            count += 1
    return count

 

이와 같이 itertools.combinations(nums, 3)을 하면 nums 배열에서 중복을 허용하지 않는 3개의 원소를 무작위로 골라 가능한 모든 조합을 만든다.

'CodingTest > 프로그래머스' 카테고리의 다른 글

BFS - 단어 변환  (0) 2024.10.18
[야근 지수] - 최대힙 이용  (0) 2024.10.18
[프로그래머스] 타겟 넘버  (0) 2024.08.05
[프로그래머스]게임 맵 최단거리  (0) 2024.08.05
[프로그래머스] 할인 행사  (0) 2024.08.03

최소힙과 최대힙에 대한 설명

 

힙(Heap)은 이진 트리 기반의 자료구조로, 특정한 규칙을 따릅니다. 힙에는 두 가지 주요 형태가 있습니다:

 

1. 최소힙(Min Heap): 부모 노드의 값이 자식 노드보다 항상 작거나 같은 이진 트리입니다. 즉, 가장 작은 값이 루트에 위치하게 됩니다.

2. 최대힙(Max Heap): 부모 노드의 값이 자식 노드보다 항상 크거나 같은 이진 트리입니다. 가장 큰 값이 루트에 위치합니다.

 

이 두 힙은 주로 우선순위 큐(Priority Queue)로 사용되며, 값을 정렬된 순서대로 유지해야 하는 문제를 해결하는 데 매우 효율적입니다.

 

최소힙의 특징

 

가장 작은 값을 빠르게 찾고 싶을 때 유용합니다.

삽입과 삭제 연산은 O(log n)의 시간 복잡도를 가집니다.

파이썬에서는 heapq 라이브러리를 사용해 최소힙을 구현할 수 있습니다.

 

최대힙의 특징

 

가장 큰 값을 빠르게 찾고 싶을 때 유용합니다.

삽입과 삭제 연산은 O(log n)의 시간 복잡도를 가집니다.

파이썬의 heapq는 기본적으로 최소힙으로 동작하므로, 최대힙을 구현하려면 음수로 변환해서 사용합니다.

 

최소힙/최대힙을 사용하는 상황

 

1. 우선순위가 있는 작업 처리

힙은 우선순위 큐(Priority Queue)로 사용되며, 가장 높은(작거나 큰) 우선순위를 가진 요소를 빠르게 처리해야 할 때 매우 유용합니다.

예시: 병원 응급실, 작업 스케줄링 등 우선순위가 있는 작업을 먼저 처리할 때.

2. K번째 최소/최대 값을 구할 때

힙을 사용하면 K번째로 작은/큰 값을 찾는 연산을 매우 효율적으로 할 수 있습니다.

최소/최대 값을 찾아야 하는 문제에서는 힙이 시간 복잡도를 크게 줄여줍니다.

3. 실시간으로 가장 큰 값이나 작은 값을 관리할 때

데이터가 계속해서 추가될 때, 매번 최소값이나 최대값을 빠르게 추적해야 할 경우 힙이 유용합니다.

예시: 스트리밍 데이터에서 상위 K개의 값을 추적하는 문제.

4. 정렬된 데이터를 유지해야 할 때

힙을 사용하면 데이터를 정렬된 상태로 유지하면서도 삽입/삭제가 빠릅니다.

예시: 실시간으로 정렬된 데이터를 처리하는 알고리즘.

 

최소힙/최대힙의 사용 예시

 

최소힙 예시:

 

import heapq

 

h = []

heapq.heappush(h, 5)

heapq.heappush(h, 3)

heapq.heappush(h, 8)

 

print(heapq.heappop(h))  # 3, 최소값부터 꺼내짐

print(heapq.heappop(h))  # 5

print(heapq.heappop(h))  # 8

 

최대힙 예시 (음수를 이용):

 

import heapq

 

h = []

heapq.heappush(h, -5)  # 음수로 저장하여 최대힙 구현

heapq.heappush(h, -3)

heapq.heappush(h, -8)

 

print(-heapq.heappop(h))  # 8, 최대값을 꺼내려면 다시 양수로 변환

print(-heapq.heappop(h))  # 5

print(-heapq.heappop(h))  # 3

 

힙을 사용하면 효율적인 경우

 

데이터가 계속해서 들어오고, 그중 가장 큰 값이나 가장 작은 값을 실시간으로 추적해야 하는 경우.

데이터가 계속 추가되지만 매번 전체를 정렬할 필요는 없고, 가장 큰 값이나 작은 값만 찾고 싶을 때.

K번째로 큰 값/작은 값을 구하는 문제를 효율적으로 해결하고 싶을 때.

 

비효율적인 경우

 

이미 정렬된 배열이 주어졌을 때 굳이 힙을 사용할 필요가 없습니다.

힙의 삽입과 삭제는 O(log n)이므로, 단순 정렬이 더 나은 선택일 수 있는 경우도 있습니다.

 

최소힙/최대힙의 시간 복잡도

 

삽입 및 삭제: O(log n)

최소/최대값 조회: O(1) (루트 노드이기 때문에 바로 조회 가능)

 

힙은 실시간 데이터 처리우선순위가 중요한 문제에서 매우 효율적이므로 이러한 문제를 해결할 때 사용하는 것이 좋습니다.

 

 

예시 : 

"명예의 전당"이라는 TV 프로그램에서는 매일 1명의 가수가 노래를 부르고, 시청자들의 문자 투표수로 가수에게 점수를 부여합니다. 매일 출연한 가수의 점수가 지금까지 출연 가수들의 점수 중 상위 k번째 이내이면 해당 가수의 점수를 명예의 전당이라는 목록에 올려 기념합니다. 즉 프로그램 시작 이후 초기에 k일까지는 모든 출연 가수의 점수가 명예의 전당에 오르게 됩니다. k일 다음부터는 출연 가수의 점수가 기존의 명예의 전당 목록의 k번째 순위의 가수 점수보다 더 높으면, 출연 가수의 점수가 명예의 전당에 오르게 되고 기존의 k번째 순위의 점수는 명예의 전당에서 내려오게 됩니다.

이 프로그램에서는 매일 "명예의 전당"의 최하위 점수를 발표합니다. 예를 들어, k = 3이고, 7일 동안 진행된 가수의 점수가 [10, 100, 20, 150, 1, 100, 200]이라면, 명예의 전당에서 발표된 점수는 아래의 그림과 같이 [10, 10, 10, 20, 20, 100, 100]입니다.

명예의 전당 목록의 점수의 개수 k, 1일부터 마지막 날까지 출연한 가수들의 점수인 score가 주어졌을 때, 매일 발표된 명예의 전당의 최하위 점수를 return하는 solution 함수를 완성해주세요.

제한사항
  • 3 ≤ k ≤ 100
  • 7 ≤ score의 길이 ≤ 1,000
    • 0 ≤ score[i] ≤ 2,000

입출력 예kscoreresult
3 [10, 100, 20, 150, 1, 100, 200] [10, 10, 10, 20, 20, 100, 100]
4 [0, 300, 40, 300, 20, 70, 150, 50, 500, 1000] [0, 0, 0, 0, 20, 40, 70, 70, 150, 300]

입출력 예 설명

입출력 예 #1

  • 문제의 예시와 같습니다.

입출력 예 #2

  • 아래와 같이, [0, 0, 0, 0, 20, 40, 70, 70, 150, 300]을 return합니다. 

이 문제는 루프를 돌며 매 루프마다 최솟값을 찾아야 한다. 또한, 매번 스택을 업데이트 해줘야 하는데, 최솟값을 배열의 맨 마지막에 넣어야 한다. 힙이 없다면, 매 루프마다 append -> 배열을 정렬해야 한다. 하지만 정렬의 시간 복잡도는 O(n log n)이므로 큰 입력에 대해서는 비효율적이다.

 

어차피 이 문제에서 우리가 찾아야 하는건 '최솟값' 이다. 

 

루프가 n번 돌고, 매번마다 리스트를 정렬하고 거기서 최솟값을 찾는건 비효율적이다. 따라서, 힙을 쓰면 실시간으로 따로 정렬이나 min()함수 없이 최솟값을 트래킹 할 수 있다.

import heapq

def solution(k, score):
    answer = []
    h = []
    
    for s in score:
        if len(h) < k:
            heapq.heappush(h, s)  # 힙에 값 추가
        else:
            # 현재 힙의 최솟값보다 큰 경우 힙의 최솟값을 대체
            if h[0] < s:
                heapq.heapreplace(h, s)  # 가장 작은 값을 pop하고 s 삽입
        answer.append(h[0])  # 현재 힙에서 최솟값을 answer에 추가
        
    return answer

 

질문 1: h[0]이 최솟값인가?

 

최소힙에서 h[0]은 항상 최소값이다. 파이썬의 heapq 라이브러리는 기본적으로 최소힙을 사용하므로, 가장 작은 값이 루트에 위치합니다.

따라서 h[0]최소값을 의미한다.

 

질문 2: heapreplace가 뭐냐?

 

heapq.heapreplace(h, s)최소힙에서 가장 작은 값(루트 노드)을 꺼낸 뒤, 새로운 값을 힙에 추가하는 함수다. 즉, 기존의 최솟값을 삭제하고, 새로운 값을 삽입하는 연산이다.

이 함수는 다음과 같은 두 가지 동작을 하나의 연산으로 처리한다:

1. 최소값을 꺼냄 (heappop(h))

2. 새로운 값을 삽입 (heappush(h, s))

이 과정에서 힙은 여전히 최소힙의 조건을 만족하게끔 유지된다.

 

예시:

import heapq

h = [1, 3, 5, 7, 9]

heapq.heapreplace(h, 4)

print(h)  # 출력: [3, 4, 5, 7, 9]

 

1. h에서 최소값 1이 삭제되고, 4가 삽입되었다.

2. 결과적으로 힙의 최소값은 3으로 바뀌었고, 힙의 다른 요소들은 최소힙의 조건을 만족하도록 재정렬되었다.

 

heapreplace()와 heappushpop()의 차이:

 

heapreplace()값을 무조건 삭제한 후 새로운 값을 삽입.

반면에, heappushpop()새로운 값을 먼저 힙에 삽입한 뒤, 가장 작은 값(루트 노드)을 제거하는 방식으로 동작. 삽입하는 값이 힙의 최솟값보다 작으면, 그대로 그 값이 빠지고 힙은 그대로 유지.

 

예시 비교:

import heapq

h = [1, 3, 5, 7, 9]

# heapreplace: 기존 최솟값을 삭제하고 4를 삽입

heapq.heapreplace(h, 4)

print(h)  # 출력: [3, 4, 5, 7, 9]

# heappushpop: 먼저 2를 삽입하고 최솟값을 제거

heapq.heappushpop(h, 2)

print(h)  # 출력: [3, 4, 5, 7, 9] (2는 최솟값이기 때문에 삽입되자마자 빠짐)

 

따라서, heapreplace()는 값 대체가 필요한 경우 사용되고, heappushpop()은 삽입한 값이 최소값일 때 효율적으로 처리할 수 있는 방법입니다.

오늘 코딩 테스트를 풀며 파이썬의 람다 함수에 대해 쓰다가, 확실히 알고 넘어가는 게 좋을 것 같아 정리하고 넘어가기로 했다!

 

내가 주로 사용했던 람다 함수는 특정 기준으로 정렬할 때 사용했다. 예를 들어, {'a': 10, 'b': 20, 'c': 30}이라는 딕셔너리가 있다고 해 보자. 이 딕셔너리에서 keyvalue를 기준으로 정렬하고 싶을 때 말이다.

 

어떠한 특정 기준으로 정렬하려면 파이썬의 sorted() 함수를 사용하면 된다.

 

sorted()는 원본 데이터를 정렬하지 않고, 정렬된 새로운 결과값을 반환하므로 이를 다른 변수에 할당해야 한다.

 

목표: 딕셔너리의 value를 기준으로 정렬한 후, 다시 딕셔너리 형태로 반환하기

 

temp = {'a': 30, 'b': 60, 'c': 10}

sorted_dict = dict(sorted(temp.items(), key=lambda x: x[1]))

결과: {'c': 10, 'a': 30, 'b': 60}

 

여기서 주의할 점은 딕셔너리를 sorted() 함수로 정렬할 때, 기본적으로는 key 값이 기준이 된다는 것이다. 그래서 value를 기준으로 정렬하려면 먼저 temp.items()(key, value) 쌍에 접근해야 한다.

 

또 하나의 예시: 문자열을 특정 문자를 기준으로 정렬하기

 

문제를 풀다가 sorted() 함수의 또 다른 유용한 기능을 발견했다. 예를 들어, 여러 개의 문자열을 담고 있는 배열이 있고, 이 배열을 특정 인덱스의 문자를 기준으로 정렬한다고 해 보자.

temp = ["abce", "abcd", "cdx"]

 

이 문자열들에서 3번째 인덱스의 문자를 기준으로 정렬하려면, 각 단어의 3번째 문자는 'c', 'c', 'x'가 된다. 이를 기준으로 정렬하면 다음과 같다.

sorted_arr = list(sorted(temp, key=lambda x: x[3]))

 

결과는 ['abce', 'abcd', 'cdx']가 된다. 그런데 만약 같은 문자를 가진 경우, 이를 전체 문자열을 기준으로 정렬하고 싶다면 어떻게 할까?

 

즉, 같은 3번째 문자를 가진 ['abce', 'abcd']가 있을 때, 전체 문자열을 기준으로 ['abcd', 'abce', 'cdx']로 정렬하고 싶은 경우다.

 

이때는 이렇게 해결할 수 있다:

sorted_arr = list(sorted(temp, key=lambda x: (x[3], x)))

이 코드는 3번째 문자를 기준으로 정렬하되, 3번째 문자가 같은 경우 전체 문자열 x를 기준으로 정렬한다. 이렇게 하면 최종 결과는 ['abcd', 'abce', 'cdx']가 된다.

 

이 코드는 문자열 배열 temp두 가지 기준으로 정렬하는데, 두 번째 기준이 첫 번째 기준과 같을 때만 적용된다. 

 

코드 설명:

1. sorted() 함수: sorted()는 배열을 정렬하는 함수로, 정렬된 새로운 리스트를 반환한다. 여기서는 temp 리스트를 정렬하고 있다.

2. key=lambda x: (x[3], x):

key는 정렬할 때 기준이 되는 값을 지정하는 인자다. 여기서는 람다 함수를 사용해서 정렬 기준을 두 가지로 나눈다.

첫 번째 기준: x[3]으로, 각 문자열의 3번째 인덱스의 문자를 기준으로 정렬한다.

두 번째 기준: x로, 전체 문자열을 기준으로 정렬한다. 이 두 번째 기준은 첫 번째 기준(3번째 문자)이 동일할 때만 적용된다.

 

작동 원리:

 

파이썬의 sorted() 함수는 튜플로 정렬할 때, 첫 번째 요소를 먼저 비교하고, 첫 번째 요소가 같으면 두 번째 요소를 비교한다.

lambda x: (x[3], x)두 가지 기준을 갖는 튜플 (x[3], x)를 반환한다:

첫 번째 기준: x[3]은 각 문자열의 3번째 문자다. 이를 기준으로 정렬한다.

두 번째 기준: x전체 문자열이다. 만약 3번째 문자가 같다면, 문자열 전체를 기준으로 사전순 정렬한다.

 

예시로 살펴보기:

 

temp = ["abce", "abcd", "cdx"]

 

1. 첫 번째 기준: 각 문자열의 3번째 문자는 다음과 같다:

'abce': 3번째 문자 'c'

'abcd': 3번째 문자 'c'

'cdx': 3번째 문자 'x'

2. 첫 번째 기준으로 정렬:

'abce''abcd'는 3번째 문자가 같으므로 같은 그룹으로 묶인다.

'cdx'는 3번째 문자가 'x'라서 나중에 온다.

3. 두 번째 기준: 3번째 문자가 같은 **‘abce’**와 **‘abcd’**의 경우, 이제 전체 문자열을 기준으로 사전순으로 정렬된다:

'abcd''abce'보다 사전순으로 앞서므로 먼저 위치하게 된다.

 

최종 결과:

 

결과적으로, 정렬된 리스트는 ['abcd', 'abce', 'cdx']가 된다.

 

요약:

 

sorted(temp, key=lambda x: (x[3], x))첫 번째로 3번째 문자를 기준으로, 두 번째로 전체 문자열을 기준으로 정렬하는 방식이다.

만약 3번째 문자가 같을 때전체 문자열을 사전순으로 정렬해주는 역할을 한다.

 

🔒 문제 분석

알겠지만 easy 수준의 문제는 문제 분석 능력을 따로 필요로 하지 않는다. '알고리즘' 보단 어떤 '자료구조'를 쓸지만 떠올리면 되지만, 레벨 2 이상을 올라가면 자료구조, 알고리즘 모두 고려를 해야 하는 상황이기 때문에 문제 분석을 해야한다.

 

1. 모든 조합을 탐색해야 하는 상황

  • 주어진 숫자들을 가지고 더하거나 빼서 타겟 넘버를 만들어야 한다.
  • 각 숫자에 대해 - ,+ 의 옵션이 있으므로 이를 통해 가능한 모든 조합을 탐색 해야한다.
  • "모든 조합을 탐색"해야 하는 문제는 보통 DFS나 BFS로 접근한다.

2. 재귀적 구조

  • 각 숫자에 대해 두가지 선택지를 고려해야 하는데, 이는 재귀적으로 각 선택지를 탐색하는 구조와 유사하다.
  • 특히, 특정 조건을 만족하는 모든 경로를 찾거나 모든 가능한 경로를 탐색하는 문제는 DFS로 해결하는 경우가 많다.

3. 문제의 조건

  • 주어진 숫자들의 순서를 바꾸지 않고 각 숫자를 더하거나 빼서 타겟 넘버를 만드는 방법의 수를 찾아야 한다.
  • 이는 각 단계마다 두 가지 선택지를 가지는 트리 구조로 생각할 수 있습니다. DFS는 트리의 모든 경로를 탐색하는 데 적합하다.

이러한 문제를 보고 DFS를 떠올리게 되는 핵심 포인트는:

  • 모든 가능한 조합을 탐색해야 하는 요구사항
  • 재귀적 탐색이 필요함
  • 경로의 누적 합을 관리해야 함

DFS는 두 가지 방식으로 구현될 수 있다:

  1. 재귀 호출을 통한 구현
  2. 스택을 이용한 반복적 구현

재귀 호출 방식이 더 직관적이고 간단하기 때문에 많이 사용된다. 하지만 재귀 깊이가 깊어질 경우 스택 오버플로우 문제가 발생할 수 있으며, 이럴 때는 반복적 구현이 유용할 수 있다.

 

def solution(numbers, target):
    def dfs(index, current_sum):
        if index == len(numbers):
            return 1 if current_sum == target else 0
        
        add_case = dfs(index + 1, current_sum + numbers[index])
        subtract_case = dfs(index + 1, current_sum - numbers[index])
        
        return add_case + subtract_case

    return dfs(0, 0)

 

- 재귀적으로 호출할 dfs라는 함수를 선언 해준다. 우리가 필요한것은 target에 도달했는지 확인을 하기 위한 current_sum과 index를 파라미터로 받는다.

 

- 이 함수가 호출되면, 먼저 파라미터로 받은 인덱스가 현재 입력값으로 받은 numbers의 길이와 일치하는지 확인한 후(리스트에 끝에 도달했음을 의미), 만약 현재 리스트 끝에 도달했고, current_sum이 target과 일치한다면 1을 반환하고, 그렇지 않다면 0을 반환한다. 여기서 1을 반환하는건 경우의 수 카운트 +1 이라고 생각하면 쉽다.

 

-다음으로, 2가지의 케이스(+, -)를 담당할 재귀문을 작성 해준다.

 

- add_case는 다음 인덱스와 현재까지의 합에서 현재 검사중인 요소를  '더해' 재귀문을 호출한다.

- subtract_case는 다음 인덱스와 현재까지의 합에서 현재 검사중인 요소를 '빼서' 재귀문을 호출한다.

 

 

🔍 재귀...백트래킹... 하아

글을 쓰다 보니 작년 자구알고 수업때 재귀를 공부하다가 고통받았던 기억이 나 다시 한번 재귀 + 백트래킹을 좀 더 자세히 살펴보고 넘어 가보자.

 

재귀 함수 호출은 실제로 함수 호출 스택에 쌓인다. 각 재귀 호출은 함수 호출 스택에 새로운 프레임을 추가하고, 해당 호출이 완료되면 스택에서 제거(pop)된다. 이 과정은 재귀 호출이 진행되는 동안 함수 호출 순서와 현재 상태를 관리하는 데 사용된다.

 

 재귀 함수의 스택 동작

예를 들어, `numbers = [1, 1, 1, 1, 1]`이고 `target = 3`인 경우를 다시 살펴보자.

재귀 호출 순서와 스택 동작

1. 초기 호출: `dfs(0, 0)` 호출:
   - `index = 0`, `curr_sum = 0`
   - 호출 스택: `[dfs(0, 0)]`

2. 첫 번째 숫자에 대해:
   - `add_case = dfs(1, 1)` 호출:
     - `index = 1`, `curr_sum = 1`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1)]`

3. 두 번째 숫자에 대해:
   - `add_case = dfs(2, 2)` 호출:
     - `index = 2`, `curr_sum = 2`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2)]`

4. 세 번째 숫자에 대해:
   - `add_case = dfs(3, 3)` 호출:
     - `index = 3`, `curr_sum = 3`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3)]`

5. 네 번째 숫자에 대해:
   - `add_case = dfs(4, 4)` 호출:
     - `index = 4`, `curr_sum = 4`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3), dfs(4, 4)]`

6. 다섯 번째 숫자에 대해:
   - `add_case = dfs(5, 5)` 호출:
     - `index = 5`, `curr_sum = 5`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3), dfs(4, 4), dfs(5, 5)]`
     - 조건 `index == len(numbers)`이 참이므로, `curr_sum == target`를 확인하고, `0`을 반환.
     - 스택에서 `dfs(5, 5)`가 제거되고, `dfs(4, 4)`로 돌아감.
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3), dfs(4, 4)]`

7. 백트래킹
   - `dfs(4, 4)`에서 `subtract_case = dfs(5, 3)` 호출:
     - `index = 5`, `curr_sum = 3`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3), dfs(4, 4), dfs(5, 3)]`
     - 조건 `index == len(numbers)`이 참이므로, `curr_sum == target`를 확인하고, `1`을 반환.
     - 스택에서 `dfs(5, 3)`가 제거되고, `dfs(4, 4)`로 돌아감.
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3), dfs(4, 4)]`
     - `dfs(4, 4)`에서 `add_case + subtract_case = 0 + 1 = 1` 반환.
     - 스택에서 `dfs(4, 4)`가 제거되고, `dfs(3, 3)`로 돌아감.
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3)]`

8. 세 번째 숫자에 대해:
   - `dfs(3, 3)`에서 `subtract_case = dfs(4, 2)` 호출:
     - `index = 4`, `curr_sum = 2`
     - 호출 스택: `[dfs(0, 0), dfs(1, 1), dfs(2, 2), dfs(3, 3), dfs(4, 2)]`

이와 같은 방식으로 재귀 호출은 계속해서 스택에 쌓이고, 기저 조건에 도달하면 반환하면서 스택에서 제거된다. 

요약

- 재귀 호출 스택: 각 함수 호출은 스택에 쌓인다. 재귀 호출이 반환될 때마다 스택에서 제거된다.
- 백트래킹: 한 경로의 탐색이 끝나면(재귀 호출이 반환되면) 스택에서 제거되고, 이전 호출로 돌아가서 다음 경로를 탐색한다.
- 함수 호출 순서: 각 함수 호출은 순차적으로 진행되며, 호출이 완료되면 스택에서 제거되고, 다음 경로를 탐색하기 위해 이전 상태로 돌아간다.

 

+ Recent posts