이번에 주어진 과제는 총 7문제였다. 주로 자바와 친해지는 문제들인것 같았다. 첫번째 문제를 봤는데 생각보다 어려워서 막막했다. 1번부터 이렇게 어려운데 7문제를 다 풀 수 있을지 걱정이 앞섰다. 1번문제를 풀고 2번부터 5번까지는 그래도 할만했다. 5번까지 풀고 자신감이 생긴 상태로 6번으로 넘어갔는데 막막했다. 여태까지와는 다른 유형의 문제가 나와서 어렵게 느껴졌다.
우아한테크코스에서는 교육생(이하 크루) 간 소통 시 닉네임을 사용한다. 간혹 비슷한 닉네임을 정하는 경우가 있는데, 이러할 경우 소통할 때 혼란을 불러일으킬 수 있다.
혼란을 막기 위해 크루들의 닉네임 중 같은 글자가 연속적으로 포함 될 경우 해당 닉네임 사용을 제한하려 한다. 이를 위해 같은 글자가 연속적으로 포함되는 닉네임을 신청한 크루들에게 알려주는 시스템을 만들려고 한다.
신청받은 닉네임 중 같은 글자가 연속적으로 포함 되는 닉네임을 작성한 지원자의 이메일 목록을 return 하도록 solution 메서드를 완성하라.
제한사항
두 글자 이상의 문자가 연속적으로 순서에 맞추어 포함되어 있는 경우 중복으로 간주한다.
크루는 1명 이상 10,000명 이하이다.
이메일은 이메일 형식에 부합하며, 전체 길이는 11자 이상 20자 미만이다.
신청할 수 있는 이메일은 email.com 도메인으로만 제한한다.
닉네임은 한글만 가능하고 전체 길이는 1자 이상 20자 미만이다.
result는 이메일에 해당하는 부분의 문자열을 오름차순으로 정렬하고 중복은 제거한다.
실행 결과 예시
forms : [ ["jm@email.com", "제이엠"], ["jason@email.com", "제이슨"], ["woniee@email.com", "워니"], ["mj@email.com", "엠제이"], ["nowm@email.com", "이제엠"] ]
result : ["jason@email.com", "jm@email.com", "mj@email.com"]
문제를 읽고 어떻게 코드를 구성할지 생각해봤다.
1) 이중 리스트 안에 인덱스 [1]에 있는 요소를 검사
2) 인덱스[1]의 String을 쪼개서 k=0부터 (k,k+1)을 다른 리스트들의 인덱스[1]과
3) j = 0부터 (j,j+1)과 비교, 언제까지? j<length까지
4) 만약 같으면 그 리스트의 인덱스 저장
5) 이걸 일차 리스트의 길이만큼 반복
6) 닉네임 중복되는 리스트의 인덱스 [0]을 반환
처음에는 이런식으로 반복문만을 사용하도록 코드를 구성했다. 이론상으로 맞다고 생각해서 일단 짜는데 생각처럼 되지 않았다. 그래서 코딩 잘하는 친구한테 이런 방식으로 하는게 맞냐고 물어봤는데 '문제에서 크루가 만명까지 있을수 있으니 이런식으로 짜면 시간이 오래걸릴수 있으니 HashSet과 HashMap이라는 개념을 찾아서 해봐라' 라고 해서 방식을 바꿔보기로 했다.
HashSet과 HashMap이라는 이름을 들어보기는 했는데 정확히는 몰라서 찾아보면서 했다.
Set은 중복을 허용하지 않아서 중복되는 이메일을 검사할 때 활용했고
HashSet answerList = new HashSet<>(); // 중복되는 이메일을 저장할 HashSet
HashMap은 키와 밸류값으로 저장되는 자료구조인데 닉네임은 중복되면 안되니까 키로 저장하고 그 닉네임의 인덱스를 밸류로 저장해줬다.
HashMap<String, Integer> formMap = new HashMap<>(); // 닉네임을 키, 인덱스를 밸류로 저장하는 hashmap
public static List<String> compareNickname(List<List<String>> forms) {
HashMap<String, Integer> formMap = new HashMap<>(); // 닉네임을 키, 인덱스를 밸류로 저장하는 hashmap
List<Integer> indexList = new ArrayList<>(); // 중복되는 인덱스를 저장할 리스트
HashSet<String> answerList = new HashSet<>(); // 중복되는 이메일을 저장할 HashSet
for (int i = 0; i < forms.size(); i++) { // 주어진 이중 리스트의 크기만큼 반복
String nickname = forms.get(i).get(1); // 검사할 닉네임 가져오기
for (int j = 0; j < nickname.length() - 1; j++) { // 닉네임의 길이만큼 반복
String twoChars = nickname.substring(j, j + 2); // 두개씩 쪼개서 twoChars에 저장
if (formMap.containsKey(twoChars)) { // 해시맵에 키가 있으면
indexList.add(formMap.get(twoChars)); // 중복된 폼의 인덱스를 indexList에 추가
indexList.add(i); // 현재 인덱스 indexList에 추가
formMap.put(twoChars, i); // 중복된 폼의 인덱스를 현재 폼의 인덱스로 변경
} else { // 해시맵에 키가 없으면
formMap.put(twoChars, i); // 해시맵에 twoChars 추가
}
}
}
for (int l = 0; l < indexList.size(); l++) {
answerList.add(forms.get(indexList.get(l)).get(0)); // 중복된 폼의 인덱스에 해당하는 이름을 answerList에 추가
}
List<String> answer = new ArrayList<>(answerList);
return answer;
}
}
아직 자바에 익숙하지 않아서 메소드를 잘 나누지 못하고 코드가 난잡한데 코드를 많이 짜보면서 익숙해져야겠다.
문제를 풀면서 변수명이나 메소드명을 최대한 짧게 하려고 줄였는데 이는 다른 사람들과의 프로젝트를 진행할 때 좋지 않은 습관이라는 소리를 들었다. 짧게 하지 않아도 되니까 변수명이나 메소드명을 보고 그들이 무슨 동작을 하는지 알아볼수 있도록 이름을 짓자.