Algorithm, kakao2018 프렌즈4블록(17679)
어려웠던점
- 개념적으로 해결할 방법은 알아냈으나, 코드로 구현하기가 어려웠다.
- 맵을 새로 리뉴얼 하는 부분이 어려웠다 (해결 코드의 down()함수)
- 네개를 비교 하는 부분은 for문과 배열을 이용해서 쉽게 구현할 수 있었다
풀이
- 내가 푼 풀이
- 검색을 빨리 하기 위해 hashmap을 사용했고, str1, str2의 max,min을 구했다
- 두개씩 쪼개는 부분이나 hashmap에 넣는것은 같은 동작이므로 함수로 구현하는게 좋을것같다
- 다른 사람의 풀이
- ArrayList로 구현했다. 합집합 = 전체집합 - 교집합 을 이용해서 빠르게 해결했다
내 풀이
public int solution(String str1, String str2) {
int answer = 0;
HashMap<String, Integer> hm1 = new HashMap<>();
HashMap<String, Integer> hm2 = new HashMap<>();
List<String> stringArray1 = new ArrayList<>();
List<String> stringArray2 = new ArrayList<>();
str1 = str1.toLowerCase();
str2 = str2.toLowerCase();
// 두개씩 쪼개서 문자만 넣기
String pattern = "^[a-zA-Z]*$";
for (int i=0; i<str1.length()-1; i++) {
String s1 = (String) str1.substring(i, i+2);
if (Pattern.matches(pattern, s1) == true)
stringArray1.add(s1);
}
for (int i=0; i<str2.length()-1; i++) {
String s2 = (String) str2.substring(i, i+2);
if (Pattern.matches(pattern, s2) == true)
stringArray2.add(s2);
}
// <쪼갠것, 쪼갠것들 개수> 해쉬맵을 이용
for (int i=0; i<stringArray1.size(); i++) {
if ( hm1.containsKey(stringArray1.get(i)) ){
hm1.put(stringArray1.get(i), hm1.get(stringArray1.get(i))+1 );
}
else
hm1.put(stringArray1.get(i), 1);
}
for (int i=0; i<stringArray2.size(); i++) {
if ( hm2.containsKey(stringArray2.get(i)) ){
hm2.put(stringArray2.get(i), hm2.get(stringArray2.get(i))+1 );
}
else
hm2.put(stringArray2.get(i), 1);
}
// str1, str2 각각에 중복된것이 있는지 찾기, 해쉬맵을 이용하여 검색을 빠르게 했다
Iterator<String> keySetIterator = hm1.keySet().iterator();
float max = 0, min = 0;
while(keySetIterator.hasNext()) {
String key = keySetIterator.next();
// 중복된것이 있다면 최소, 최댓값을 찾고 str2에서 중복된것을 삭제한다
if (hm2.containsKey(key) == true) {
max += Math.max(hm1.get(key), hm2.get(key));
min += Math.min(hm1.get(key), hm2.get(key));
hm2.remove(key);
}
// 중복된것이 없다면 최소값은 0이고 최대값은 해당 값이다
else {
max += hm1.get(key);
}
}
// 중복된것은 직전에 모두 삭제 했으므로 남은 것들을 돌며 최대값을 찾아준다
keySetIterator = hm2.keySet().iterator();
while(keySetIterator.hasNext()) {
String key = keySetIterator.next();
max += hm2.get(key);
}
if (min == 0 && max == 0)
answer = 65536;
else
answer = (int)Math.floor(min/max * 65536);
return answer;
}
다른풀이
public int solution(String str1, String str2) {
List list1 = subset(str1.toLowerCase());
List list2 = subset(str2.toLowerCase());
int intersection = 0;
List<Integer> check = new ArrayList<Integer>(); // 교집합 구할 떄, 중복제거
for (int a = 0; a < list1.size(); a++) { // 교집합 개수 구하기
String s1 = (String) list1.get(a);
for (int b = 0; b < list2.size(); b++) {
String s2 = (String) list2.get(b);
// s1과 일치하는 s2가 있고, s2에 있는걸 넣은적이 없다면 추가한다
if (s1.equals(s2) && !check.contains(b)) {
intersection++;
// s1과 일치 하는 s2를 찾으면 그 위치를 저장해서 다음 s1과 해당 값을 비교해서 같을때 또 다시 입력하지 않도록 한다.
check.add(b);
// s1과 일치하는 s2를 찾으면 교집합에 넣어주고 끝내고 다음 s1을 확인한다.
break;
}
}
}
// !!!!!!!!!왕충격....
int union = list1.size() + list2.size() - intersection; // 합집합
if (union == 0 && intersection == 0) {
return 65536;
}
return (int) (((float) intersection / union) * 65536);
}
// 문자열 s의 다중집합
public List subset(String s) {
List<String> list = new ArrayList<String>();
char[] arr = s.toCharArray();
int size = arr.length - 1;
String str;
int start = 0;
int end = 1;
while (end <= size) {
str = String.valueOf(arr[start]) + String.valueOf(arr[end]);
boolean isMatch = Pattern.matches("^[a-z]*$", str); // 부분집합의 원소가 영어로만 구성되어 있는지 확인
if (isMatch) {
list.add(str);
}
start++;
end++;
}
return list;
}
Reference