Post

πŸ’ͺ🏻 programmers 고득점 Kit - ν•΄μ‹œ(Hash)

πŸ’ͺ🏻 programmers 고득점 Kit - ν•΄μ‹œ(Hash)

ν•΄μ‹œ(Hash)

κ³ μ •λœ 크기둜 값을 λ°”κΎΈλŠ” ν•¨μˆ˜λ‚˜ μ•Œκ³ λ¦¬μ¦˜. 이 결과둜 λ§Œλ“€μ–΄μ§„ 값을 ν•΄μ‹œμ½”λ“œ(hash code) ν˜Ήμ€ ν•΄μ‹œ κ°’(hash value)라고 λΆ€λ₯Έλ‹€.

ν•΄μ‹œλŠ” μ™œ μ‚¬μš©ν•˜λŠ” κ²ƒμΌκΉŒ?

  • 보톡 μ±…μ—λŠ” λͺ©μ°¨κ°€ μ‘΄μž¬ν•œλ‹€. 예λ₯Όλ“€μ–΄ 1,000νŽ˜μ΄μ§€κ°€ λ„˜λŠ” μ±…μ—μ„œ μ–΄λ–€ λ‚΄μš©μ„ 찾을 λ•Œ λͺ©μ°¨κ°€ μ—†κ±°λ‚˜ 운이 λ‚˜μ˜λ‹€λ©΄ 1,000νŽ˜μ΄μ§€μ—μ„œ ν•΄λ‹Ή λ‚΄μš©μ„ 찾을 수 μžˆλ‹€. ν•˜μ§€λ§Œ λͺ©μ°¨κ°€ μžˆλ‹€λ©΄ μ›ν•˜λŠ” λ‚΄μš©μ„ λΉ λ₯΄κ²Œ 찾을 수 μžˆκ²Œλœλ‹€.

-> 이처럼 μ‰½κ²Œ 찾을 수 μžˆλ„λ‘ λ„μ™€μ£ΌλŠ” λͺ©μ°¨λŠ” ν•΄μ‹œμ½”λ“œ(hash code)λ₯Ό μ˜λ―Έν•œλ‹€.

-> κ³ μ •λœ ν¬κΈ°λŠ” λͺ©μ°¨μ˜ 개수λ₯Ό μ˜λ―Έν•œλ‹€.

즉, ν•΄μ‹œλŠ” 보닀 λΉ λ₯΄κ²Œ μ°ΎκΈ°μœ„ν•΄ μ‘΄μž¬ν•œλ‹€.

ν•΄μ‹œ ν•¨μˆ˜(hash function) : ν•΄μ‹œ μ½”λ“œλ₯Ό λ§Œλ“€μ–΄λ‚΄λŠ” ν•¨μˆ˜λ₯Ό 의미

πŸ”Š 쒋은 ν•΄μ‹œ ν•¨μˆ˜ 쑰건

  1. 계산 속도가 빨라야 ν•œλ‹€.
  2. κ²°κ³Ό 값이 λ‹€μ–‘ν•΄μ•Ό ν•œλ‹€.


πŸ”Š ν•΄μ‹œ 좩돌

μ„œλ‘œ λ‹€λ₯Έ λŒ€μƒ(key κ°’)이 λ™μΌν•œ ν•΄μ‹œ 값을 κ°€μ§€λŠ” ν˜„μƒ

❓ ν•΄μ‹œ μΆ©λŒμ€ μ™œ λ°œμƒν• κΉŒ?

ν•΄μ‹œ μΆ©λŒμ€ μ™„λ²½ν•œ ν•΄μ‹œ ν•¨μˆ˜ κ΅¬ν˜„μ˜ μ–΄λ €μ›€μ—μ„œ λ°œμƒν•œλ‹€. ν•΄μ‹œ ν•¨μˆ˜λŠ” μž…λ ₯κ°’μ˜ λ²”μœ„κ°€ 사싀상 λ¬΄ν•œλŒ€μ— 가깝기 λ•Œλ¬Έμ—, λ‹€μ–‘ν•œ μž…λ ₯값을 κ³ μ •λœ 크기의 좜λ ₯κ°’μœΌλ‘œ λ§€ν•‘ν•˜λŠ” κ³Όμ •μ—μ„œ 좩돌이 λ°œμƒν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, μž…λ ₯값은 λ¬Έμžμ—΄, 숫자 λ“± λ‹€μ–‘ν•œ λ°μ΄ν„°λ‘œ μ΄λ£¨μ–΄μ§ˆ 수 μžˆμ§€λ§Œ, ν•΄μ‹œ ν•¨μˆ˜λŠ” κ³ μ •λœ 크기의 좜λ ₯κ°’(예: 4λ°”μ΄νŠΈ μ •μˆ˜ν˜• λ˜λŠ” 256λΉ„νŠΈ κ°’ λ“±)으둜 λ³€ν™˜ν•œλ‹€. μ΄λŸ¬ν•œ μ œν•œλœ 곡간 λ‚΄μ—μ„œ μ„œλ‘œ λ‹€λ₯Έ μž…λ ₯값이 λ™μΌν•œ 좜λ ₯값을 κ°€μ§ˆ μˆ˜λ°–μ— μ—†λŠ” κ²½μš°κ°€ μƒκΈ°λŠ”λ°, 이λ₯Ό ν•΄μ‹œ 좩돌이라고 ν•œλ‹€.


ν•΄μ‹œ 좩돌 ν•΄κ²° 방법

πŸ“Œ κ°œλ³„ 체이닝(seperate chaining) : 뢄리연결법

  • 좩돌이 λ°œμƒν•˜λ©΄ μ—°κ²°λœ μƒˆλ‘œμš΄ 곡간을 μ‚¬μš©ν•˜λŠ” 방법 -> LinkedList

1

이미지 좜처

  1. ν‚€(key)의 ν•΄μ‹œ 값을 κ³„μ‚°ν•œλ‹€.
  2. ν•΄μ‹œ 값을 μ΄μš©ν•΄ λ°°μ—΄μ˜ 인덱슀λ₯Ό κ΅¬ν•œλ‹€.
  3. 같은 μΈλ±μŠ€κ°€ μžˆλ‹€λ©΄ LinkedList둜 μ—°κ²°ν•œλ‹€.

좩돌이 λ°œμƒν•œ 'μœ€μ•„', 'μ„œν˜„'은 λ‹€μŒ μ•„μ΄ν…œμΈ 'μ„œν˜„'의 ν˜•νƒœλ‘œ μ„œλ‘œ μ—°κ²° 리슀트둜 μ—°κ²°λœλ‹€.

-> μ‰½κ²Œ μ•„νŒŒνŠΈμ²˜λŸΌ λͺ¨μ—¬μžˆλ‹€κ³  μƒκ°ν•˜λ©΄ μ’‹λ‹€. 'μœ€μ•„'λŠ” 2μΈ΅ 1호, 'μ„œν˜„'은 2μΈ΅ 2호

  • LinkedListλ₯Ό μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 보닀 μœ μ—°ν•˜κ²Œ μ‚¬μš©ν•  수 있고 ν•΄μ‹œ 값을 κ·ΈλŒ€λ‘œ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ LinkedListλ₯Ό μ‚¬μš©ν•œλ‹€λŠ” 것은 좔가적인 곡간이 ν•„μš”ν•˜λ‹€λŠ” μ˜λ―Έμ΄λ‹€. λ”°λΌμ„œ μ—°μ†λœ 데이터가 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— μΊμ‹œμ˜ 도움을 λ°›κΈ° μ–΄λ ΅λ‹€.

  • LinkedListλŠ” 검색 μ‹œ O(n) 만큼의 μ‹œκ°„μ΄ μ†Œμš”λœλ‹€.


πŸ“Œ μ˜€ν”ˆ μ–΄λ“œλ ˆμ‹±(oepn addressing) : κ°œλ°©μ£Όμ†Œλ²•

  • 좩돌이 λ°œμƒν•˜λ©΄ λ‹€λ₯Έ ν•΄μ‹œ μ½”λ“œ(버킷)λ₯Ό μ‚¬μš©ν•˜λŠ” 방법. μΈμ ‘ν•œ 빈 곡간에 μ €μž₯

1

이미지 좜처

  1. μ„ ν˜• 탐사(Linear Probing) : 좩돌 μ‹œ λ‹€μŒ 버킷, ν˜Ήμ€ λͺ‡κ°œλ₯Ό κ±΄λ„ˆλ›°μ–΄ 데이터 μ‚½μž…
  2. 제곱 탐사(Quadratic Probing) : 좩돌 μ‹œ 제곱만큼 κ±΄λ„ˆλ›΄ 버킷에 데이터λ₯Ό μ‚½μž…
  3. 이쀑 ν•΄μ‹œ(Double Hashing) : 좩돌 μ‹œ λ‹€λ₯Έ ν•΄μ‹œ ν•¨μˆ˜λ₯Ό ν•œλ²ˆ 더 μ μš©ν•œ κ²°κ³Όλ₯Ό 이용
  • κ³ μ •λœ 크기의 배열을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 좔가적인 곡간을 ν•„μš”λ‘œ ν•˜μ§€ μ•ŠλŠ”λ‹€. 데이터가 적을 땐 κ°œλ³„ 체이닝보닀 쒋은 μ„±λŠ₯을 보인닀. μ—°μ†λœ 곡간을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— CPUκ°€ λΉ λ₯΄κ²Œ 찾을 수 있기 λ•Œλ¬Έμ΄λ‹€.

  • ν•˜μ§€λ§Œ 데이터가 λ§Žμ•„μ§€λ©΄ μΊμ‹œμ—μ„œ μ°ΎλŠ” 값을 κΊΌλ‚΄μ˜¬ ν™•λ₯ μ΄ 쀄어듀어 쒋은 μΊμ‹œμ˜ μ„±λŠ₯을 κΈ°λŒ€ν•  수 μ—†λ‹€.

  • 좩돌이 λ°œμƒν–ˆμ„ λ•Œ λ‹€μŒ 빈 곡간을 μ°ΎκΈ° μ–΄λ €μ›Œμ§€κ³  값이 자주 μΆ”κ°€λ˜κ³  μ‚­μ œλœλ‹€λ©΄ μ„±λŠ₯이 λ–¨μ–΄μ§„λ‹€.


HashMap

key의 쀑볡을 ν”Όν•˜κΈ° μœ„ν•΄ ν•΄μ‹œλ₯Ό μ‚¬μš©ν•˜λŠ” Map μžλ£Œκ΅¬μ‘°μ΄λ‹€.

  • Java의 HashMap은 ν•΄μ‹œ μΆ©λŒμ„ κ°œλ³„ 체이닝 λ°©μ‹μœΌλ‘œ λŒ€μ‘ν•œλ‹€.

보쑰 ν•΄μ‹œ ν•¨μˆ˜ : ν•΄μ‹œ 값이 더 κ· λ“±ν•˜κ²Œ λ‚˜μ˜¬ 수 있게 λ„μ™€μ£ΌλŠ” ν•¨μˆ˜


HashTable

  • HashMapκ³Ό μœ μ‚¬ν•œ 자료ꡬ쑰

  • Mapμ—μ„œλŠ” key와 value λͺ¨λ‘ null을 μ‚¬μš©ν•  수 μžˆμ§€λ§Œ Tableμ—μ„œλŠ” μ‚¬μš©ν•  수 μ—†λ‹€.

-> ν•΄λ‹Ή 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ Java 1.5 이후뢀터 ConcurrentHashMap을 μ§€μ›ν•œλ‹€.

  • HashTable은 Thread-safe ν•˜μ§€λ§Œ μ„±λŠ₯이 λΆ€μ‘±ν•΄μ„œ ConcurrentHashMap을 μ‚¬μš©ν•΄μ„œ μ“°λ ˆλ“œ μ•ˆμ •μ„±μ„ μ±™κΈ°λ©΄ λœλ‹€.


HashMap과 HashTable 차이점

  • HashTable은Java의 API. μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬κ°€ λ§Œλ“€μ–΄μ§€κΈ° 전에 μ‘΄μž¬ν•˜λ˜ κ²ƒμ΄μ§€λ§Œ ν˜Έν™˜μ„ μœ„ν•΄ 남겨둔 것이고 HashMap은 Java Collections Framework API이닀.

  • HashTable은 syncronized ν‚€μ›Œλ“œκ°€ μžˆμ–΄ 동기화λ₯Ό μ§„ν–‰ν•˜μ§€λ§Œ HashMap의 경우 syncronized ν‚€μ›Œλ“œκ°€ μ—†μ–΄μ„œ λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ 데이터 무결성을 보μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.

  • HashTable은 Key에 null이 λ“€μ–΄μ˜€λ©΄ NullPointerErrorλ₯Ό λ˜μ§€μ§€λ§Œ HashMap은 Key에 null이 λ“€μ–΄μ˜€λ©΄ 0으둜 ν•΄μ‹±ν•˜μ—¬ μ €μž₯ν•œλ‹€.


HashSet

  • λ‚΄λΆ€μ μœΌλ‘œ HashMap을 μ‚¬μš©ν•œλ‹€.

  • Map 자료 ꡬ쑰의 keyκ°€ 쀑볡될 수 μ—†λ‹€λŠ” 점을 μ΄μš©ν•΄ setμ΄λΌλŠ” 자료 ꡬ쑰의 νŠΉμ§•μ„ μ‚΄λ Έλ‹€.

  • keyλ‘œλŠ” μ €μž₯ν•  데이터λ₯Ό, value 값은 λ‚΄λΆ€μ μœΌλ‘œ μƒμ„±λ˜μ–΄ μžˆλŠ” dummyλ₯Ό μ‚¬μš©ν•œλ‹€.


Red-Black Tree

LinkedListλŠ” 자료 ꡬ쑰 검색 μ‹œ O(n)의 μ‹œκ°„μ„ μ†Œμš”ν•œλ‹€. -> 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ JavaλŠ” Tree 자료 ꡬ쑰λ₯Ό ν™œμš©ν•œλ‹€.

JavaλŠ” 좩돌이 λ°œμƒν•œ 경우 Seperate Chaining을 LinkedList둜 κ΅¬ν˜„ν•΄ μΆ©λŒμ— λŒ€μ‘ν•˜μ˜€λ‹€. κ·ΈλŸ¬λ‚˜ Java 8λΆ€ν„° λ°μ΄ν„°μ˜ κ°œμˆ˜κ°€ 일정 이상일 λ•ŒλŠ” 기쑴에 μ‚¬μš©ν•˜λ˜ LinkedList λŒ€μ‹  Treeλ₯Ό μ‚¬μš©ν•œλ‹€.

데이터가 n번 μΆ©λŒν•΄ μ—°κ²° 리슀트의 n번째 λ…Έλ“œμ— μ €μž₯λœλ‹€λ©΄ ν•΄λ‹Ή λ…Έλ“œ 탐색을 μœ„ν•œ μ‹œκ°„λ³΅μž‘λ„λŠ” O(n)이 λœλ‹€.

λ”°λΌμ„œ 좩돌이 λ§Žμ•„μ§ˆμˆ˜λ‘ 효율이 점점 λ–¨μ–΄μ§€κΈ° λ•Œλ¬Έμ— 일정 좩돌 μˆ˜κ°€ λ„˜μ–΄κ°€λ©΄ 트리 방식을 μ‚¬μš©ν•΄ μ„±λŠ₯을 O(log n)으둜 κ°œμ„ ν•œλ‹€.

1

Java8의 HashMap에 λ“€μ–΄κ°€μ„œ ν™•μΈν•˜λ©΄ μƒμˆ˜λ‘œ 기쀀이 μ •ν•΄μ Έ μžˆλ‹€.

ν•˜λ‚˜μ˜ ν•΄μ‹œ 버킷에 8개의 key-value 쌍이 λͺ¨μ΄λ©΄ LinkedListλ₯Ό Tree둜 λ³€κ²½ν•˜κ³  데이터λ₯Ό μ‚­μ œν•΄ κ°œμˆ˜κ°€ 6κ°œκ°€ 되면 λ‹€μ‹œ LinkedList둜 λ³€κ²½ν•œλ‹€.

μ—¬κΈ°μ„œ 차이가 1이 μ•„λ‹Œ 2인 μ΄μœ λŠ” μ–΄λ–€ ν•œ key-value 쌍이 λ°˜λ³΅λ˜μ–΄ μ‚½μž…/μ‚­μ œκ°€ λ˜λŠ” 경우 λΆˆν•„μš”ν•˜κ²Œ Tree와 LinkedListλ₯Ό 반볡적으둜 λ³€κ²½ν•΄ μ„±λŠ₯ μ €ν•˜κ°€ λ°œμƒν•  수 있기 λ•Œλ¬Έμ΄λ‹€.

또, λ°μ΄ν„°μ˜ κ°œμˆ˜κ°€ 6 μ΄ν•˜μΌ λ•Œ LinkedList둜 λ‹€μ‹œ λ³€κ²½ν•˜λŠ” μ΄μœ λŠ” 데이터 κ°œμˆ˜κ°€ 적을 λ•Œ LinkedList의 μ΅œμ•…μ˜ 경우 μˆ˜ν–‰ μ‹œκ°„ 차이가 λ§Žμ§€ μ•Šκ³  TreeλŠ” LinkedList보닀 λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ΄ 많기 λ•Œλ¬Έμ΄λ‹€.

특히 Red-Black Tree λΌλŠ” 검색에 μ΅œμ ν™”λœ 트리 ꡬ쑰λ₯Ό μ‚¬μš©ν•œλ‹€.

1 이미지 좜처

  • JavaλŠ” λ°μ΄ν„°μ˜ 일정 좩돌 μˆ˜κ°€ λ„˜μ–΄κ°€λ©΄ Red-Black Tree둜 데이터λ₯Ό μ €μž₯ν•œλ‹€. μš°μ„  데이터 κ°œμˆ˜κ°€ 많기 μ „μ—λŠ” Node 객체둜 LinkedListλ₯Ό κ΅¬ν˜„ν–ˆμ§€λ§Œ Red-Black TreeλŠ” λ‹¨μˆœ Node 객체둜 κ΅¬ν˜„ν•  수 μ—†λ‹€.
  1. Node 객체λ₯Ό treeifyBin λ©”μ„œλ“œλ₯Ό 톡해 TreeNode 객체둜 λ°”κΏ”μ€€λ‹€.

  2. treeify λ©”μ„œλ“œλ₯Ό 톡해 parent, left, right ν•„λ“œμ™€ Red-Black Tree λ‘œμ§μ„ μœ„ν•œ μ μ ˆν•œ 값을 λ„£μ–΄μ€€λ‹€.

πŸ”Š Java 8 μ΄ν›„λ‘œ, 기쑴에 LinkedList둜 Chainning 기법을 μ‚¬μš©ν•œ TreeMap을 Red-Black Tree둜 λ³€κ²½ν•˜μ—¬ μ‹œκ°„λ³΅μž‘λ„λ₯Ό O(n)μ—μ„œ O(logn)으둜 쀄일 수 μžˆλ‹€.


포켓λͺ¬ - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

ν•΄λ‹Ή λ¬Έμ œλŠ” λ§€κ°œλ³€μˆ˜λ‘œ μž…λ ₯ λ°›λŠ” μ •μˆ˜μ—μ„œ N/2 마리λ₯Ό 선택할 λ•Œ κ°€μž₯ λ§Žμ€ μ’…λ₯˜μ˜ 포켓λͺ¬μ„ μ„ νƒν•˜λŠ” 방법을 κ΅¬ν•˜λŠ” λ¬Έμ œμ΄λ‹€.

[3, 1, 2, 3] 일 경우

  • (3, 1)
  • (3, 2)
  • (3, 3)
  • (1, 2)
  • (1, 3)
  • (2, 3)

으둜 6κ°€μ§€μ˜ κ²½μš°μ΄μ§€λ§Œ 포켓λͺ¬ μ’…λ₯˜ 수의 μ΅œλŒ€κ°’μ€ 2이닀.

[3, 3, 3, 2, 2, 2] 일 경우

  • (2, 3) 으둜 μ΅œλŒ€κ°’μ€ 2이닀.

μ—¬κΈ°μ„œ HashSet은 쀑볡을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€.

즉, [3, 1, 2, 3]의 set.size()λŠ” 3이닀.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.*;
class Solution {
    public int solution(int[] nums) {
        int answer = 0;
        int num = nums.length/2;
        
        HashSet<Integer> set = new HashSet<>();
        
        for(int i=0;i<nums.length;i++)
        {
            set.add(nums[i]);
        }
        
        if(num < set.size())
        {
            answer = num;
        }
        else{
            answer = set.size();
        }
        
        return answer;
    }
}
  1. λ¨Όμ € HashSet을 μ„ μ–Έν•˜κ³  numsλ₯Ό set에 μΆ”κ°€ν•œλ‹€.

  2. num의 값이 set의 μ‚¬μ΄μ¦ˆλ³΄λ‹€ μž‘λ‹€λ©΄ num이 닡이 λœλ‹€.

  • [3, 1, 2, 3] μ—μ„œ num = 2, set.size() = 3인데, num < set.size()μ΄λ―€λ‘œ num이 λ‹Ά
  1. num의 값이 set의 μ‚¬μ΄μ¦ˆλ³΄λ‹€ 크닀면 set.size()κ°€ 닡이 λœλ‹€.
  • [3, 3, 3, 2, 2, 2] μ—μ„œ num = 3, set.size() = 2 인데, num > set.size()μ΄λ―€λ‘œ set.size()κ°€ λ‹Ά


μ™„μ£Όν•˜μ§€ λͺ»ν•œ μ„ μˆ˜ - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

ν•΄λ‹Ή λ¬Έμ œλŠ” λ§ˆλΌν†€μ— μ°Έμ—¬ν•œ μ„ μˆ˜λ“€μ˜ 이름이 λ‹΄κΈ΄ λ°°μ—΄ participant, μ™„μ£Όν•œ μ„ μˆ˜λ“€μ˜ 이름이 λ‹΄κΈ΄ λ°°μ—΄ completion, μ™„μ£Όν•˜μ§€ λͺ»ν•œ μ„ μˆ˜μ˜ 이름을 κ΅¬ν•˜λŠ” λ¬Έμ œμ΄λ‹€.

μ—¬κΈ°μ„œ μ°Έκ°€μž 쀑에 λ™μΌν•œ 이름이 μžˆμ„ 수 있고 key-valueλ₯Ό μ‚¬μš©ν•˜μ—¬ λΉ λ₯΄κ²Œ μ°Ύμ•„μ•Ό λ˜λ―€λ‘œ HashMap을 μ‚¬μš©ν•œλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.*;
class Solution {
    public String solution(String[] participant, String[] completion) {
        String answer = "";
        
        Map<String, Integer> map = new HashMap<>();
        
        for(String s : participant)
        {
            map.put(s, map.getOrDefault(s, 0)+1);
        }
        
        for(String s : completion)
        {
            map.put(s, map.get(s)-1);
        }
        
        for(String s : map.keySet())
        {
            if(map.get(s) > 0)
            {
                answer = s;
             //   break;
            }
        }
        
        return answer;
    }
}
  1. λ¨Όμ € HashMap을 μ„ μ–Έν•œλ‹€.

  2. ν–₯μƒλœ for문을 μ΄μš©ν•΄μ„œ s에 participant의 값을 λŒ€μž…ν•˜κ³  map에 put λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ μΆ”κ°€ν•œλ‹€. μ—¬κΈ°μ„œ map.getOrDefault(s, 0)λŠ” ν•΄λ‹Ή 이름 sκ°€ 이미 μ €μž₯λ˜μ–΄ 있으면 κ·Έ 값을 κ°€μ Έμ˜€κ³  κ·Έλ ‡μ§€ μ•Šμ„ 경우 0을 λ°˜ν™˜ν•œλ‹€. +1을 ν•΄μ€€ μ΄μœ λŠ” 횟수λ₯Ό μ„ΈκΈ° μœ„ν•¨μ΄λ‹€.

  3. ν–₯μƒλœ for문을 μ΄μš©ν•΄μ„œ s에 completion 값을 λŒ€μž…ν•˜κ³  map에 put λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ μΆ”κ°€ν•œλ‹€. μ—¬κΈ°μ„œ map.get(s)-1은 ν˜„μž¬ map에 μ €μž₯된 sλ₯Ό κ°€μ Έμ™€μ„œ -1을 μˆ˜ν–‰ν•œλ‹€.

  4. map.keySet()은 map의 λͺ¨λ“  ν‚€λ₯Ό μˆœνšŒν•œλ‹€.


μ „ν™”λ²ˆν˜Έ λͺ©λ‘ - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

ν•΄λ‹Ή λ¬Έμ œλŠ” μ „ν™”λ²ˆν˜ΈλΆ€μ— 적힌 μ „ν™”λ²ˆν˜Έλ₯Ό 담은 배열이 μ£Όμ–΄μ§€κ³  μ–΄λ–€ λ²ˆν˜Έκ°€ λ‹€λ₯Έ 번호의 접두어에 μžˆμ„ 경우 false, κ·Έλ ‡μ§€ μ•Šμ„ 경우 trueλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό κ΅¬ν•˜λŠ” 것이닀.

  1. HashMap을 μ„ μ–Έν•œλ‹€.

  2. map에 phone_book λ°°μ—΄μ˜ 값을 μΆ”κ°€ν•œλ‹€.

  3. 이쀑 for문을 μ‚¬μš©ν•˜μ—¬ map에 νŠΉμ • ν‚€κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•œλ‹€. μ—¬κΈ°μ„œ substring을 μ‚¬μš©ν•˜μ—¬ 0λΆ€ν„° μžκΈ°μžμ‹ κΉŒμ§€ ν™•μΈν•œλ‹€.

  • [12, 13, 123]을 μ˜ˆμ‹œλ‘œ λ“ λ‹€λ©΄ phone_book[2] 일 λ•Œ, substring(0,1) -> 1, substring(0,1) ->2 μ΄λ―€λ‘œ β€œ12”와 κ²ΉμΉ˜λ―€λ‘œ falseκ°€ λœλ‹€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.*;
class Solution {
    public boolean solution(String[] phone_book) {
       
        Map<String, Integer> map = new HashMap<>();
        
        for(String s : phone_book)
        {
            map.put(s, map.getOrDefault(s,0));
        }
        
        for(int i=0;i<phone_book.length;i++)
        {
            for(int j=0;j<phone_book[i].length();j++)
            {
                if(map.containsKey(phone_book[i].substring(0,j)))
                {
                    return false;
                }
            }
        }
        
        return true;
    }
}

λ°°μ—΄μ˜ length : μƒμˆ˜ κ°’μœΌλ‘œ μ €μž₯된 크기λ₯Ό λ‹¨μˆœνžˆ 읽음. μžλ°”μ—μ„œ μ†μ„±μœΌλ‘œ κ΅¬ν˜„λ˜μ–΄ 있고 μ΄λŠ” λ°°μ—΄μ˜ 크기λ₯Ό μƒμˆ˜ κ°’μœΌλ‘œ μ €μž₯ν•˜κ³  λ°˜ν™˜ν•˜λŠ” 방식.

λ¬Έμžμ—΄μ˜ length() : λ¬Έμžμ—΄μ˜ 길이λ₯Ό κ³„μ‚°ν•˜κ±°λ‚˜ λ°˜ν™˜ν•˜λŠ” 둜직이 포함될 수 있음. λ©”μ„œλ“œλ‘œ κ΅¬ν˜„λ˜μ–΄ 있고 λ‚΄λΆ€μ μœΌλ‘œ λ¬Έμžμ—΄μ˜ 길이λ₯Ό κ³„μ‚°ν•΄μ„œ λ°˜ν™˜ν•¨.

κ·Έ μ™Έμ˜ μ‹ λ°•ν–ˆλ˜ 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.*;
class Solution {
    public boolean solution(String[] phone_book) {
        boolean answer = true;
        
        Arrays.sort(phone_book);
        
        for(int i=0;i<phone_book.length-1;i++)
        {
            if(phone_book[i+1].startsWith(phone_book[i]))
            {
                return false;
            }
        }
        
        return answer;
    }
}


μ˜μƒ - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

ν•΄λ‹Ή λ¬Έμ œλŠ” 각 μ’…λ₯˜λ³„λ‘œ μ΅œλŒ€ 1κ°€μ§€ μ˜μƒλ§Œ μ°©μš©ν•  수 있으며 μ˜·μ„ μ‘°ν•©ν•˜μ—¬ λ‚˜μ˜€λŠ” 경우의 개수λ₯Ό κ΅¬ν•˜λŠ” 것이닀.

1
[["yellow_hat", "headgear"], ["blue_sunglasses", "eyewear"], ["green_turban", "headgear"]]

ν•΄λ‹Ή 예제λ₯Ό 보면 headgear이 (yellow_hat, green_turban) 2개, eyewear이 (blue_sunglasses) 1κ°œμ΄λ‹€. 그러면 λ‚˜μ˜€λŠ” κ²½μš°λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  1. yellow_hat
  2. blue_sunglasses
  3. green_turban
  4. yellow_hat + blue_sunglasses
  5. green_turban + blue_sunglasses

μ΄λŠ” headgear 개수 2와 eyewear의 개수 1에 1μ”© λ”ν•œ λ’€ κ³±ν•˜κ³  λ§ˆμ§€λ§‰μ— λͺ¨λ‘ μ•ˆ μž…λŠ” 경우(1)λ₯Ό λΉΌμ£Όλ©΄ λœλ‹€.

  • headgear: 2개의 μ•„μ΄ν…œ + 1 (아무것도 μ•ˆ μž…μŒ) β†’ 3κ°€μ§€ 선택
  • eyewear: 1개의 μ•„μ΄ν…œ + 1 (아무것도 μ•ˆ μž…μŒ) β†’ 2κ°€μ§€ 선택

μ‘°ν•©μ˜ μ „κ°œ

  1. yellow_hat을 μ„ νƒν–ˆμ„ λ•Œ:

    • yellow_hat + blue_sunglasses
    • yellow_hat + 아무것도 μ•ˆ μž…μŒ
  2. green_turban을 μ„ νƒν–ˆμ„ λ•Œ:

    • green_turban + blue_sunglasses
    • green_turban + 아무것도 μ•ˆ μž…μŒ
  3. 아무것도 μ•ˆ μž…μŒμ„ μ„ νƒν–ˆμ„ λ•Œ:

    • 아무것도 μ•ˆ μž…μŒ + blue_sunglasses
    • 아무것도 μ•ˆ μž…μŒ + 아무것도 μ•ˆ μž…μŒ

(2+1)Γ—(1+1)=6이고 아무것도 μž…μ§€ μ•ŠλŠ” 경우λ₯Ό μ œμ™Έν•΄μ•Ό ν•˜λ―€λ‘œ 1을 λΉΌμ€€λ‹€. 6βˆ’1=5κ°€ λœλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.*;
class Solution {
    public int solution(String[][] clothes) {
        int answer = 1;
        
        Map<String, Integer> map = new HashMap<>();
        
        for(String[] s : clothes)
        {
            map.put(s[1], map.getOrDefault(s[1], 0)+1);
        }
        
        for(String s: map.keySet())
        {
            answer *= map.get(s) + 1;
        }
        
        return answer-1;
    }
}
  • map.put(s[1], map.getOrDefault(s[1], 0)+1); λ₯Ό 보면 map에 key λΆ€λΆ„μ—λŠ” s[1]의 값을 λ„£κ³ , value λΆ€λΆ„μ—λŠ” s[1]이 있으면 κ·Έ 값을 λ„£κ³  μ—†μœΌλ©΄ 0+1을 λŒ€μž…ν•œλ‹€.

  • map.keySet()은 map의 λͺ¨λ“  ν‚€λ₯Ό 순회

  • map.get(s) λŠ” map에 μ €μž₯된 sλ₯Ό κ°€μ Έμ˜΄.


달리기 κ²½μ£Ό - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.*;
class Solution {
    public String[] solution(String[] players, String[] callings) {
        Map<String, Integer> map = new HashMap<>();
        
        for(int i=0;i<players.length;i++)
        {
            map.put(players[i], i); // 이름, μˆœμœ„
        }
        
        for(String calling : callings)
        {
            int grade = map.get(calling); // 호좜된 μ΄λ¦„μ˜ ν˜„μž¬ μˆœμœ„
            
            String forwardCalling = players[grade-1]; // ν•΄λ‹Ή μˆœμœ„ μ§μ „μ˜ players 이름을 κ°€μ Έμ˜΄
            
            players[grade-1] = calling; // ν˜ΈμΆœν•œ ν”Œλ ˆμ΄μ–΄λ₯Ό μ•žμœΌλ‘œ 이동
            map.put(calling, grade -1); // mapμ—μ„œ μˆœμœ„ ν•œμΉΈ μ•žμœΌλ‘œ 이동
            
            players[grade] = forwardCalling; // μ•žμ— 있던 ν”Œλ ˆμ΄μ–΄ λ’€λ‘œ 이동
            map.put(forwardCalling, grade); //mapμ—μ„œ μˆœμœ„ μ—…λ°μ΄νŠΈ
        }
        return players;
    }
}


베슀트 앨범 - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

μ•„λž˜λŠ” 제곡된 Java μ½”λ“œμ— λŒ€ν•΄ ν•œ 쀄씩 주석을 μΆ”κ°€ν•˜μ—¬ ν•΄μ„ν•œ κ²ƒμž…λ‹ˆλ‹€. 그리고 Entry에 λŒ€ν•œ μ„€λͺ…도 ν¬ν•¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.


μ½”λ“œ μ„€λͺ… 및 주석

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.*; // λ‹€μ–‘ν•œ Java μœ ν‹Έλ¦¬ν‹° ν΄λž˜μŠ€λ“€(ArrayList, HashMap, Entry λ“±)을 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ import
import java.util.Map.Entry; // Map의 λ‚΄λΆ€ μΈν„°νŽ˜μ΄μŠ€ Entryλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄ import

class Solution {
    public int[] solution(String[] genres, int[] plays) { // μž₯λ₯΄ λ°°μ—΄κ³Ό μž¬μƒ 수 배열을 μž…λ ₯λ°›μ•„ 베슀트 앨범에 ν¬ν•¨λœ λ…Έλž˜ 인덱슀λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
        int[] answer = {}; // μ΅œμ’… κ²°κ³Όλ₯Ό 담을 λ°°μ—΄ μ„ μ–Έ
        
        ArrayList<Integer> answerList = new ArrayList<>(); // κ²°κ³Όλ₯Ό μ €μž₯ν•  ArrayList(λ™μ μœΌλ‘œ 크기λ₯Ό 관리 κ°€λŠ₯)
        Map<String, Integer> map = new HashMap<>(); // μž₯λ₯΄λ³„ 총 μž¬μƒ 수λ₯Ό μ €μž₯ν•  HashMap
        
        for(int i = 0; i < genres.length; i++) { 
            // 각 μž₯λ₯΄λ³„λ‘œ μž¬μƒ 수 합계λ₯Ό κ³„μ‚°ν•˜μ—¬ HashMap에 μ €μž₯
            map.put(genres[i], map.getOrDefault(genres[i], 0) + plays[i]); 
            // map.getOrDefault(key, defaultValue)λŠ” keyκ°€ μ‘΄μž¬ν•˜λ©΄ 값을 λ°˜ν™˜ν•˜κ³ , μ—†μœΌλ©΄ κΈ°λ³Έκ°’(defaultValue)을 λ°˜ν™˜
        }
        
        // map의 entrySet()을 μ‚¬μš©ν•΄ μž₯λ₯΄μ™€ μž¬μƒ 수λ₯Ό List둜 λ³€ν™˜
        List<Entry<String, Integer>> genresList = new ArrayList<>(map.entrySet()); 
        // μž₯λ₯΄λ³„ 총 μž¬μƒ 수λ₯Ό κΈ°μ€€μœΌλ‘œ λ‚΄λ¦Όμ°¨μˆœ μ •λ ¬
        Collections.sort(genresList, new Comparator<Entry<String, Integer>>() {
            public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue()); 
                // o2의 κ°’(μž¬μƒ 수)이 더 크면 μ•žμ— μ˜€λ„λ‘ μ •λ ¬
            }
        });
        
        // μ •λ ¬λœ μž₯λ₯΄λ³„λ‘œ 반볡
        for (Entry<String, Integer> entry : genresList) {
            Map<Integer, Integer> temp = new HashMap<>(); // ν˜„μž¬ μž₯λ₯΄μ— μ†ν•œ 곑의 μΈλ±μŠ€μ™€ μž¬μƒ 수λ₯Ό μ €μž₯ν•  μž„μ‹œ HashMap
            for (int i = 0; i < genres.length; i++) { 
                if (entry.getKey().equals(genres[i])) { 
                    // ν˜„μž¬ μž₯λ₯΄(entry.getKey())에 μ†ν•œ 곑인지 확인
                    temp.put(i, plays[i]); // ν•΄λ‹Ή 곑의 인덱슀(i)와 μž¬μƒ 수(plays[i])λ₯Ό μ €μž₯
                }
            }
            
            // μž₯λ₯΄ λ‚΄ 곑듀을 μž¬μƒ 수 κΈ°μ€€μœΌλ‘œ λ‚΄λ¦Όμ°¨μˆœ μ •λ ¬
            List<Entry<Integer, Integer>> songsList = new ArrayList<>(temp.entrySet());
            Collections.sort(songsList, new Comparator<Entry<Integer, Integer>>() {
                public int compare(Entry<Integer, Integer> o1, Entry<Integer, Integer> o2) {
                    return o2.getValue().compareTo(o1.getValue()); 
                    // μž¬μƒ 수 κΈ°μ€€ λ‚΄λ¦Όμ°¨μˆœ μ •λ ¬
                }
            });
            
            // μƒμœ„ 두 곑의 인덱슀λ₯Ό answerList에 μΆ”κ°€
            for (int j = 0; j < songsList.size() && j < 2; j++) { 
                answerList.add(songsList.get(j).getKey()); 
                // λ…Έλž˜μ˜ 인덱슀λ₯Ό μΆ”κ°€
            }
        }
        
        // ArrayListλ₯Ό λ°°μ—΄λ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜
        answer = new int[answerList.size()];
        for (int i = 0; i < answerList.size(); i++) {
            answer[i] = answerList.get(i);
        }
        
        return answer; // μ΅œμ’… κ²°κ³Ό λ°˜ν™˜
    }
}

Entryλž€?

  • EntryλŠ” Map μΈν„°νŽ˜μ΄μŠ€μ˜ λ‚΄λΆ€ μΈν„°νŽ˜μ΄μŠ€λ‘œ, Map에 μ €μž₯된 ν‚€-κ°’ 쌍(key-value pairs)을 λ‚˜νƒ€λ‚Έλ‹€.

  • 예λ₯Ό λ“€μ–΄, HashMapμ—μ„œ entrySet() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ λͺ¨λ“  ν‚€-κ°’ 쌍이 ν¬ν•¨λœ Set<Entry<K, V>>λ₯Ό λ°˜ν™˜ν•œλ‹€.

  • Entry<K, V> κ°μ²΄λŠ” 두 κ°€μ§€ μ£Όμš” λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•¨

    1. getKey(): ν˜„μž¬ Entry 객체의 ν‚€λ₯Ό λ°˜ν™˜.
    2. getValue(): ν˜„μž¬ Entry 객체의 값을 λ°˜ν™˜.

Entry의 μ‚¬μš© 이유

HashMap의 데이터λ₯Ό μ •λ ¬ν•˜κ±°λ‚˜ νŠΉμ • 쑰건으둜 μ²˜λ¦¬ν•  λ•Œ, key와 valueλ₯Ό ν•¨κ»˜ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ λ§Žλ‹€. μ΄λ•Œ, entrySet()을 톡해 λͺ¨λ“  ν‚€-κ°’ μŒμ„ μ‰½κ²Œ 가져와 μ •λ ¬μ΄λ‚˜ 필터링을 μˆ˜ν–‰ν•  수 μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
Map<String, Integer> map = new HashMap<>();
map.put("Pop", 500);
map.put("Rock", 300);

// entrySet()으둜 ν‚€-κ°’ μŒμ„ κ°€μ Έμ˜΄
for(Entry<String, Integer> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 좜λ ₯:
// Key: Pop, Value: 500
// Key: Rock, Value: 300

1) μž₯λ₯΄λ³„ μž¬μƒ 횟수λ₯Ό HashMap에 μ €μž₯ν•˜κ³  λ‚΄λ¦Όμ°¨μˆœ μ •λ ¬

2) λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬λœ μž₯λ₯΄λ³„λ‘œ κ³ μœ λ²ˆν˜Έμ™€ μž¬μƒνšŸμˆ˜λ₯Ό HashMap에 μ €μž₯

3) HashMap을 λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬, μž¬μƒνšŸμˆ˜κ°€ λ§Žμ€ 2개으,γ…£ 고유번호λ₯Ό λ¦¬μŠ€νŠΈμ— μ €μž₯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.*;
import java.util.Map.Entry;
class Solution {
    public int[] solution(String[] genres, int[] plays) {
        int[] answer = {};
        
        ArrayList<Integer> answerList = new ArrayList<>();
        Map<String, Integer> map = new HashMap<>();
        
        for(int i=0;i<genres.length;i++)
        {
            map.put(genres[i], map.getOrDefault(genres[i],0)+plays[i]);
        }
        
        // μž₯λ₯΄μ™€ μž¬μƒ 수λ₯Ό List둜 λ³€ν™˜
        List<Entry<String, Integer>> genresList = new ArrayList<Entry<String, Integer>>(map.entrySet());
        // μž₯λ₯΄λ³„ 총 μž¬μƒ 수λ₯Ό κΈ°μ€€μœΌλ‘œ λ‚΄λ¦Όμ°¨μˆœ μ •λ ¬
        Collections.sort(genresList, new Comparator<Entry<String, Integer>>(){
            public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2)
            {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        
        // μ •λ ¬λœ μž₯λ₯΄λ³„λ‘œ 반볡
        for(Entry<String, Integer> entry : genresList)
        {
            Map<Integer, Integer> temp = new HashMap<>();
            for(int i=0;i<genres.length;i++)
            {
                if(entry.getKey().equals(genres[i]))
                {
                    temp.put(i,plays[i]);
                }
            }
            // μž₯λ₯΄ λ‚΄ 곑듀을 μž¬μƒ 수 κΈ°μ€€μœΌλ‘œ λ‚΄λ¦Όμ°¨μˆœ μ •λ ¬
            List<Entry<Integer,Integer>> songsList = new ArrayList<Entry<Integer, Integer>>(temp.entrySet());
            Collections.sort(songsList, new Comparator<Entry<Integer, Integer>>(){
                public int compare(Entry<Integer,Integer> o1, Entry<Integer, Integer> o2)
                {
                    return o2.getValue().compareTo(o1.getValue());
                }
            });
            
            // μƒμœ„ 두 곑의 인덱슀λ₯Ό answerList에 μΆ”κ°€
            for(int j=0;j<songsList.size() && j<2; j++)
            {
                answerList.add(songsList.get(j).getKey());
            }
        }
        
        // ArrayListλ₯Ό λ°°μ—΄λ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜
        answer = new int[answerList.size()];
        for(int i=0;i<answerList.size();i++)
        {
            answer[i] = answerList.get(i);
        }
        
        return answer;
    }
}

μ°Έκ³  πŸ™‡πŸ»β€β™€οΈ

λΈ”λ‘œκ·Έ - https://codinghejow.tistory.com/408

λΈ”λ‘œκ·Έ - https://chaewsscode.tistory.com/183

This post is licensed under CC BY 4.0 by the author.