주어진 문자열을 2개씩 끊되, 알파벳으로만 이루어진 집합을 만들어 나머지 집합과 비교하는 문제.
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
class Solution {
int total = 0;
public Map<String, Integer> createMap(String s) {
Map<String, Integer> map = new HashMap<>();
String now;
for (int i = 2; i < s.length() + 1; i++) {
now = s.substring(i - 2, i);
if (now.replaceAll("[^a-z]","").length() < 2)
continue;
total++;
try {
map.put(now, map.get(now) + 1);
} catch (Exception e) {
map.put(now, 1);
}
}
return map;
}
public int solution(String str1, String str2) {
Map<String, Integer> map1 = createMap(str1.toLowerCase());
Map<String, Integer> map2 = createMap(str2.toLowerCase());
if (total == 0)
return 65536;
Set<String> set1 = new HashSet<>(map1.keySet());
Set<String> set2 = new HashSet<>(map2.keySet());
set1.retainAll(set2);
int cnt = 0;
for (String s: set1)
cnt += Math.min(map1.get(s), map2.get(s));
return (int)((double)cnt / (total - cnt) * 65536);
}
}
Map<String, Integer> map1 = createMap(str1.toLowerCase());
Map<String, Integer> map2 = createMap(str2.toLowerCase());
Map 2개를 생성하는데, 소문자로 구성되게끔 한 문자열을 넘긴다.
public Map<String, Integer> createMap(String s) {
Map<String, Integer> map = new HashMap<>();
String now;
for (int i = 2; i < s.length() + 1; i++) {
now = s.substring(i - 2, i);
if (now.replaceAll("[^a-z]","").length() < 2)
continue;
total++;
try {
map.put(now, map.get(now) + 1);
} catch (Exception e) {
map.put(now, 1);
}
}
return map;
}
HashMap을 우선 생성하고, 받은 문자열을 2글자씩 끊는다.
이 때, 소문자 알파벳을 제외한 나머지 글자들은 없앤다. 만약 글자가 한글자라도 지워진다면 for문을 재가동한다.
소문자 알파벳으로만 이뤄진 문자열을 map의 key로 넣어주며 전체 문자열의 갯수를 1 증가시킨다.
해당 key가 이미 있었을 시 value 1을 증가시켜주며, 없을 시 해당 문자열과 1을 map에 넣어준다.
그 후 map을 반환.
if (total == 0)
return 65536;
만약 아무런 문자열이 생성되지 않아 양쪽 다 빈 집합이라면 65536을 반환한다.
Set<String> set1 = new HashSet<>(map1.keySet());
Set<String> set2 = new HashSet<>(map2.keySet());
set1.retainAll(set2);
map의 key들을 set으로 만든 후 공집합화한다.
int cnt = 0;
for (String s: set1)
cnt += Math.min(map1.get(s), map2.get(s));
공집합의 문자열을 하나씩 꺼내 양쪽 집합을 확인한다. 보다 작은 수를 기준으로 공집합이 활성화되니 작은 수를 가져오게끔 한다.
return (int)((double)cnt / (total - cnt) * 65536);
cnt를 double로 만들어 소수점 결과가 나오게 한다.
total에서 중복된 cnt만큼을 빼 주고 나눈다.
65536을 곱한다.
int로 소수점을 버린 후 반환.
비효율적으로 풀었다. 다른 사람의 풀이를 참고할 것.
def solution(str1, str2):
str_group = [[], []]
str1 = str1.upper()
str2 = str2.upper()
s = [str1, str2]
for d in range(2):
for i in range(1, len(s[d])):
two_char = s[d][i - 1: i + 1]
if two_char.isalpha():
str_group[d].append(two_char)
both = []
total = str_group[0][:]
for st in str_group[1]:
if st in str_group[0]:
both.append(st)
str_group[0].remove(st)
else:
total.append(st)
return int(65536 * (len(both) / len(total) if len(total) != 0 else 1))
str_group = [[], []]
str1 = str1.upper()
str2 = str2.upper()
s = [str1, str2]
2글자 문자열만을 담을 str_group과 기존 문자열을 대문자화한 str1, str2를 선언하여 s에 담았다.
for d in range(2):
for i in range(1, len(s[d])):
two_char = s[d][i - 1: i + 1]
if two_char.isalpha():
str_group[d].append(two_char)
양쪽의 문자열을 다 확인, 2글자씩 자르고 알파벳으로만 구성된건지 확인한다.
그 후 str_group에 담는다.
both = []
total = str_group[0][:]
양 쪽 모두 존재하는 문자열을 담을 both와 첫번째 문자열에서 생성된 2글자 리스트를 복사한 total을 준비시킨다.
for st in str_group[1]:
if st in str_group[0]:
both.append(st)
str_group[0].remove(st)
else:
total.append(st)
두번째 문자열에서 생성된 2글자 문자열을 확인한다.
만약 첫번째 문자열 집합에 해당 2글자 문자열이 있다면, both에 추가하고 첫번째 문자열 집합에서 제거한다.
없다면, 전체 문자열에 추가한다.
return int(65536 * (len(both) / len(total) if len(total) != 0 else 1))
전체 문자열에 아무것도 없다면 65536을 반환.
아닐 경우 공집합의 길이 / 전체집합의 길이 * 65536을 반환한다.
파이썬 코드를 보자마자 '아, 과거의 내가 비효율적으로 풀었구나'라는 생각이 확 들었다.
코드 가독성도 그렇고, 시간도 꽤나 오래 걸릴 것이다.
과거에 비해 실력이 늘긴 늘었나 보다.
그래도.. 아직 멀었지.