import java.util.HashMap;
import java.util.HashSet;

public class Solution {
	
	// 아이디 추천
	// S(3 ~ 6 길이 영 소문자) + N(0 ~ 6 길이 숫자) 조합의 아이디를 추천한다.
	
	public static String solution(String[] registered_list, String new_id) { // 등록된 아이디 배열, 신규 아이디
		String answer = "";
		int registeredStrEndIdx = 0; // 등록된 아이디의 S + N 조합에서 S의 마지막 인덱스를 담을 변수
		int newStrEndIdx = 0; // 신규 아이디의 S + N 조합에서 S의 마지막 인덱스를 담을 변수
		String tempStr = ""; // S 부분을 담을 변수
		int tempNum = 0; // N 부분을 담을 변수
		int recommendNum = 0; // 신규 아이디가 이미 등록되어 있을 경우 추천할 숫자
        
		HashMap<String, HashSet<Integer>> hmHs = new HashMap<>();
        
		// STEP 1. 등록된 아이디 체크하며 HashMap<String, HashSet<Integer>> 구조로 key와 value 담기
		for (String str : registered_list) { // 등록된 아이디 체크
        	
			for (int i = 0; i < str.length(); i++) {
        		
				if (str.charAt(i) >= '0' && str.charAt(i) <= '9') { // S + N 조합에서 N 시작(숫자 시작) 인덱스 확인
					registeredStrEndIdx = i - 1; // 영 소문자로 구성된 문자열 S의 마지막 인덱스
					break;
				}
			}
        	
			if (registeredStrEndIdx == 0) { // strEndIdx가 그대로라면! 즉, 등록된 이 아이디가 문자열로만 이루어져 있다면(S)
        		
				if (!hmHs.containsKey(str)) { // 이미 key 값으로 갖고있는 문자열 S인지 체크
					hmHs.put(str, new HashSet<Integer>()); // 없다면 문자열 S를 key로 넣고 value값을 담을 HashSet 생성
					hmHs.get(str).add(0); // 최초 card=[0]
				}
			} else { // 등록된 이 아이디가 영 소문자 문자열 + 숫자라면(S + N)
				tempStr = str.substring(0, registeredStrEndIdx + 1); // S
				tempNum = Integer.parseInt(str.substring(registeredStrEndIdx + 1, str.length())); // N
        		
				if (!hmHs.containsKey(tempStr)) { // 이미 key 값으로 갖고있는 문자열 S인지 체크
					hmHs.put(tempStr, new HashSet<Integer>());
					hmHs.get(tempStr).add(tempNum);
				} else {
					hmHs.get(tempStr).add(tempNum);
				}
			}
        	
			registeredStrEndIdx = 0; // 다음 등록된 아이디 확인 전 초기화
		}
        
		// hmHs => {ace=[16, 17, 13, 14], banker=[0], card=[0]}
        
		// STEP 2. 신규 아이디가 사용 가능한지 확인, 사용 불가하다면 아이디 추천받기
		for (int i = 0; i < new_id.length(); i++) {
        	
			if (new_id.charAt(i) >= '0' && new_id.charAt(i) <= '9') { // 숫자 범위라면
				newStrEndIdx = i - 1;
				break;
			}
		}
        
		if (newStrEndIdx == 0) { // newStrEndIdx가 그대로라면! 즉, 신규 아이디가 문자열로만 이루어져 있다면(S)
        	
			if (!hmHs.containsKey(new_id)) { // 신규 아이디이자, 아이디의 S가 등록된 아이디의 key로 존재하지 않아 그대로 사용 가능하다면
				answer = new_id; // 신규 아이디 S를 그대로 사용하도록 함
			} else { // 신규 아이디이자, 아이디의 S가 이미 등록되어 있다면
        		
				HashSet<Integer> tempHs = hmHs.get(new_id); // 뒤에 붙일 숫자 추천을 위해 HashSet 가져오기 // 이 경우 null이 담길 수 없음
        		
				// 1. HashSet은 null 값을 저장할 수 있다. 2. null과 isEmpty는 다르다.

				while(true) { // 숫자 추천을 위해 확인 반복 // 이 경우 신규 아이디가 이미 등록되어 있는 경우이므로 tempHs에는 null이 담겨있을 수 없기 때문에 null인 경우 무시
        			
					if (tempHs.contains(recommendNum)) { // 0부터 체크 // 해당 번호가 있다면
						recommendNum++; // 있다면 1 증가
					} else { // 0부터 체크 // 해당 번호가 없다면
            			
						if (recommendNum == 0) {
							answer = new_id; // S 그대로 사용하도록 함
						} else {
							answer = new_id + Integer.toString(recommendNum); // S + 추천 숫자
						}
						break;
					}
				}
			}
		} else { // 신규 아이디가 영 소문자 문자열 + 숫자라면(S + N)
			tempStr = new_id.substring(0, newStrEndIdx + 1); // S
			tempNum = Integer.parseInt(new_id.substring(newStrEndIdx + 1, new_id.length())); // N
    		
			HashSet<Integer> tempHs = hmHs.get(tempStr); // 없으면 HashSet에 null이 담긴다.
        	
			while(true) { // 숫자 추천을 위해 확인 반복
    			
				if (tempHs == null) { // HashSet은 null 값을 저장할 수 있기 때문에 isEmpty를 써선 안된다. // N을 그대로 사용 가능하다면
					answer = tempStr + Integer.toString(tempNum); // S + N
					break;
				} else {
    				
					if (tempHs.contains(tempNum)) { // 신규 아이디와 숫자가 이미 존재한다면
						tempNum++; // 숫자 1 증가
					} else { // 사용 가능한 숫자라면
						answer = tempStr + Integer.toString(tempNum); // S + N 또는 S + 추천 숫자
						break;
					}
				}
			}
		}
        
		return answer;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String[] registered_list = {"card", "ace13", "ace16", "banker", "ace17", "ace14"}; // 배열 길이 1 ~ 100000
		String new_id = "ace15";
		
		System.out.println(solution(registered_list, new_id)); // ace15 // S(3 ~ 6 길이 영 소문자) + N(0 ~ 6 길이 숫자) 조합의 아이디 추천
	}
}

1. HashSet은 null 값을 저장할 수 있다.

2. null과 isEmpty는 다르다. (null : 인스턴스가 생성되지 않은 상태, isEmpty : 인스턴스는 생성되었으나 비어있는 상태)

 

HashMap<String, HashSet<Integer>> hmHs = new HashMap<>();

HashSet<Integer> testOneHs = hmHs.get("test"); // 이 경우 isEmpty가 아닌 null

 

HashSet<Integer> testTwoHs = new HashSet<Integer>(); // 이 경우 null이 아닌 isEmpty

 

프로그래머스 아이디 추천 문제 풀이 Java

+ Recent posts