-
Notifications
You must be signed in to change notification settings - Fork 6
2주차
Set 또는 Map은 인터페이스로 실제로 구현되지 않는 추상메서드만 가지고 있습니다. 이 추상메서드를 구현한 것이 HashSet, HashMap 같은 클래스입니다. 위 사진에서 다양한 클래스들을 확인할 수 있습니다.
Set과 HashMap은 저장 단위와 중복 허용 등의 차이가 있기 때문에 둘의 차이를 이해하고 문제 풀이에 더 적합한 방법을 찾는 것이 중요합니다.
HashMap은 키(key) 와 값(value) 쌍을 저장하는 자료구조입니다. 각 키는 고유하며 키를 사용해 원하는 값을 빠르게 검색할 수 있습니다.
HashMap은 자료구조로 배열(Array)을 사용하는데, 해싱을 통해 변환된 해시코드는 배열의 각 요소인 버킷(Bucket)의 인덱스가 됩니다. 이 인덱스를 통해 값을 빠르게 찾을 수 있습니다.
해싱은 키(key)를 해싱 함수(Hashing Function)를 이용해 정수값인 해시코드(Hashcode)로 변환하는 것을 말합니다.
- 키를 사용해 빠른 액세스 가능
- 키의 순서 보장하지 않음
- 키 중복 불가, 값 중복 가능
- 해싱 충돌 발생 가능
키는 숫자뿐만 아니라 문장까지도 가능해 그 수는 무궁무진합니다. 그러나 인덱스는 배열의 크기보다 작은 정수로 한정되어 있어 많은 키가 있다면 서로 다른 키가 동일한 인덱스를 가질 가능성이 있습니다. 이렇게 서로 다른 키가 동일한 해시 코드를 갖는 것을 해싱 충돌(Hashing Collision)이라고 합니다.
- 체이닝(Chaining)
- 개방 주소법 (Open Addressing)
- 재해싱 (Rehashing)
- 버킷 확장 (Bucket Expansion)
- 커스텀 해시 함수 사용
Set은 수학적 집합과 유사하게 동작하는 추상 자료형입니다. 주로 빠른 검색, 삽입, 삭제 연산을 위해 사용됩니다. HashMap과 다르게 키를 저장하지 않고 값만 저장합니다.
- 중복된 요소 허용하지 않음
- 순서 없음 -> 자동 정렬X
- 집합 연산 제공
- 중복된 데이터를 허용하지 않으면서 빠른 검색, 삽입, 삭제가 필요한 경우
ex) 사용자 ID 목록 관리 - 특정 값 존재 여부 판단할 경우
- 중복된 데이터 제거해야 하는 경우
- 삽입, 삭제, 검색, 크기 확인 => O(1)
- 합집합/교집합/차집합 계산 => O(n)
- 빈도 계산
- 문자열/배열에서 각 원소의 등장 횟수 세기
ex) 문자열에서 가장 많이 등장한 문자를 구하라
- 매핑 구조
- 키-값 관계를 빠르게 조회
ex) 학생 이름->점수 매핑 후 특정 학생 점수 찾기
- 인덱스 추적
- 배열에서 값과 인덱스를 매핑해 빠르게 위치 찾기
ex) 두 수의 합이 target이 되는 인덱스 찾기
- 그래프 표현
- 인접 리스트 구현 (노드->연결된 노드 리스트)
- 캐싱
- 최근 조회한 값을 저장해 빠르게 다시 접근
- 중복 제거
- 배열이나 문자열에서 중복된 원소 제거
ex) 배열에서 유니크한 숫자만 남겨라
- 존재 여부 확인
- 특정 값이 이미 등장했는지 빠르게 체크
ex) 두 배열에 공통된 원소가 있는지 확인하라
- 집합 연산
- 교집합, 합집합, 차집합 구현
ex) 두 문자열에 공통된 문자 찾기
- 사이클 탐지
- 그래프나 연결리스트에서 방문한 노드를 기록해 중복 망문 여부 확인
- 중복/존재 여부 -> Set
- 빈도/매핑/인덱스 -> HashMap
https://school.programmers.co.kr/learn/courses/30/lessons/42576
이 문제는 참가자 명단과 완주자 명단이 주어지고 참가자 중 완주하지 못한 선수를 찾는 문제입니다. 동명이인이 존재할 수 있으므로 참가자 명단 단순 소거가 아닌 빈도를 계산해야 하기 때문에 HashMap을 사용해 풀어줍니다.
import java.util.*;
class Solution {
public String solution(String[] participant, String[] completion) {
Map<String, Integer> map = new HashMap<>();
// 참가자 카운트
for (String p : participant) {
map.put(p, map.getOrDefault(p, 0) + 1);
}
// 완주자 카운트 감소
for (String c : completion) {
map.put(c, map.get(c) - 1);
}
// 값이 0이 아닌 키가 완주하지 못한 선수
for (String key : map.keySet()) {
if (map.get(key) != 0) {
return key;
}
}
return "";
}
}def solution(participant, completion):
dic = {}
# 참가자 카운트
for p in participant:
dic[p] = dic.get(p, 0) + 1
# 완주자 카운트 감소
for c in completion:
dic[c] -= 1
# 값이 0이 아닌 키 반환
for key, value in dic.items():
if value != 0:
return key- 파이썬은 딕셔너리가 HashMap과 같은 기능을 함
function solution(participant, completion) {
const map = new Map();
// 참가자 카운트
for (let p of participant) {
map.set(p, (map.get(p) || 0) + 1);
}
// 완주자 카운트 감소
for (let c of completion) {
map.set(c, map.get(c) - 1);
}
// 값이 0이 아닌 키 반환
for (let [key, value] of map) {
if (value !== 0) return key;
}
}HashMap과 Set은 모두 순서가 없는데 출력 시 순서가 보장될거라고 생각할 수 있습니다.
평균적으로는 시간복잡도가 _O(1)_이지만 최악의 경우 _O(n)_이 될 수 있어 런타임 에러가 날 수 있습니다.
키만 존재하고 값이 없는 경우에는 null 처리를 해주어야 합니다. 또한 같은 키를 입력할 경우 기존 값이 덮어씌워지는데, 누적이 필요한 상황에서는 누적 처리를 해주어야 합니다.
Input Size & Algorithm Complexity
5주차 - Two Pointers / Sliding Window
13주차 - Simulation / Implementation
백현빈 → 강민주 → 조수빈 → 임현빈 → 전병훈 → 이건희
(이후 동일한 순서로 반복)