두 문자열 사이의 자카드 유사도를 계산하는 문제입니다. 일반적인 집합과 달리 이 문제에서는 다중집합(Multiset)의 개념을 적용해야 합니다.
65536을 곱한 후 소수점 아래를 버리고 정수형으로 반환합니다.문자열 전체를 toUpperCase()로 변환하여 대소문자 구분을 없앴습니다. 이후 반복문을 돌며 substring(i, i+2)를 통해 두 글자씩 추출했습니다. 이때 정규식(Pattern.matches)을 활용해 두 글자가 모두 알파벳인 경우만 필터링했습니다.
처음에는 ArrayList와 remove() 메서드를 활용해 교집합을 구하려 했으나, 데이터가 많아질수록 효율성이 떨어질 수 있다는 점을 고려했습니다. 또한 중복된 원소의 개수를 관리하기 위해 HashMap<String, Integer>를 선택했습니다.
key: 추출된 문자열 쌍 (ex: "FR")value: 해당 쌍이 나타난 횟수다중집합에서 교집합과 합집합의 크기를 구하는 가장 효율적인 방법은 각 원소의 '빈도수'를 비교하는 것입니다.
A의 총 크기 + B의 총 크기 - 교집합 크기 공식을 사용할 수 있습니다.)import java.util.*;
import java.util.regex.*;
class Solution {
public int solution(String str1, String str2) {
String upStr1 = str1.toUpperCase();
String upStr2 = str2.toUpperCase();
Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>();
for(int i=0; i < upStr1.length() - 1; i++) {
String sub = upStr1.substring(i, i+2);
if(Pattern.matches("^[A-Z]*$", sub)) {
map1.put(sub, map1.getOrDefault(sub, 0) + 1);
}
}
for(int i=0; i < upStr2.length() - 1; i++) {
String sub = upStr2.substring(i, i+2);
if(Pattern.matches("^[A-Z]*$", sub)) {
map2.put(sub, map2.getOrDefault(sub, 0) + 1);
}
}
if(map1.isEmpty() && map2.isEmpty()) return 65536;
double intersect = 0;
double union = 0;
for(String key : map1.keySet()){
if(map2.containsKey(key)) {
int size1 = map1.get(key);
int size2 = map2.get(key);
intersect = intersect + Math.min(size1, size2);
}
}
for(String key : map1.keySet()){
if(map2.containsKey(key)) {
int size1 = map1.get(key);
int size2 = map2.get(key);
union = union + Math.max(size1, size2);
}
else {
union += map1.get(key);
}
}
for(String key : map2.keySet()) {
if(!map1.containsKey(key)) {
union += map2.get(key);
}
}
return (int)(intersect / union * 65536);
}
}
합집합이 0인 경우(두 문자열 모두 유효한 쌍이 없을 때)를 처리하지 않으면 ArithmeticException이 발생합니다. 문제 조건에 따라 공집합일 때 65536을 즉시 반환하도록 예외 처리를 해주는 것이 중요했습니다.
int 타입끼리 나눗셈을 하면 소수점이 증발하여 결과가 0이 되어버립니다. double 타입을 사용하여 계산을 진행한 후, 마지막에 (int)로 형변환을 해줌으로써 정확한 유사도를 구할 수 있었습니다.
ArrayList를 쓸 때보다 HashMap을 썼을 때 다중집합의 개념이 훨씬 명확하게 코드로 표현되었습니다. 원소의 개수를 관리해야 하는 문제에서는 Map 자료구조가 매우 강력하다는 것을 다시 한번 느꼈습니다.