[TIL] 230621 (코딩테스트: 문자열 내림차순으로 배치하기, 소수 만들기, 신규 아이디 추천)

CountryGirl·2023년 6월 21일
0

TIL

목록 보기
6/80

📌 문자열 내림차순으로 배치하기

문제점 & 시도 & 해결

문자를 큰 것부터 작은 순으로 정렬을 하는 문제이다. 대문자는 소문자보다 작은 것으로 간주해서 소문자가 대문자보다 앞으로 나와야한다.

예시 ) "Zbcdefg" ➡️ "gfedcbZ"

처음에 생각했을 때는 아스키 코드를 사용해서 대문자와 소문자를 나눈 뒤, 소문자를 먼저 정렬한 문자열 뒤에 대문자를 정렬하여 붙이려고 했다.

그래서 if 문으로 대문자와 소문자를 나눠주었다.

if (s[i] > 64 && s[i] < 91) { ... }  		// 대문자
else if (s[i] > 96 && s[i] < 123) { ... }  		// 소문자

이렇게 아스키 코드를 사용해서 대문자와 소문자를 나누고 정렬을 하여 문자열에 붙여주었다.

하지만....

문자열을 그냥 정렬하면 기본값으로 대문자가 뒤로 정렬이 된다는 것을 몰랐다....
생각해보니 아스키코드를 보았을 때, [대문자 아스키코드 < 소문자 아스키코드] 이다..

그래서 큰 것부터 작은 것을 정렬하게 되면 당연하게 소문자가 먼저 정렬이 된다.

내림차순으로 정렬을 해야하기 때문에 Collections.reverseOrder() 를 사용하였다.
역시 참조형 클래스만 Collections.reverseOrder() 를 사용할 수 있다.

Arrays.sort(sArray, Collections.reverseOrder());

📌 소수 만들기

문제점 & 시도 & 해결

주어진 숫자 중 3개의 수를 더했을 때 소수가 되는 경우의 개수를 구하는 문제이다.

예시) [1, 2, 7, 6, 4] ➡️ 4

주어진 숫자 배열에서 3개의 숫자를 고르기 위해 삼중 반복문을 만들어주었다.

for (int i = 0; i < nums.length; i++) {
	for (int j = i + 1; j < nums.length; j++) {
		for (int k = j + 1; k < nums.length; k++) {
			(...)
		}
	}
}

처음에는 더한 값을 Set에 넣어서 그 중에서 소수를 찾으려고 했다.
하지만 3개의 수를 더했을 때 소수가 되는 경우의 개수였기 때문에
1 + 2 + 4 = 7 , 2 + 4 + 1 = 7 이렇게 모두 7이 되지만 3개의 수를 골라 더했기 때문에 경우의 수가 될 수 있다.

문제를 잘 이해했던 것 같다.

그래서 처음부터 세 수를 더한 값이 소수인지 판별할 수 있도록 반복문 안에 코드를 작성하였다.

int sum = (nums[i] + nums[j] + nums[k]);
boolean check = false;
for (int n = 2; n * n <= sum; n++) {
	if(sum % n == 0) check = true;
}
if(!check) answer++;

checkfalse 로 하고 true 일 때 answer 를 카운트(++) 하였다.
for 문으로 n < sum 으로 할 경우 돌지 않아도 되는 수도 돌게 된다.
100 = 10 * 10 을 생각해보면 10까지만 돌면 된다는 것을 알 수 있다.


📌 신규 아이디 추천

문제점 & 시도 & 해결

아이디를 규칙에 맞지 않을 경우 규칙에 맞게 유사한 아이디를 추천해줘야하는 문제이다.

1. 모든 대문자를 소문자로 치환
2. 알파벳 소문자, -, _, .를 제외한 모든 문자 제거
3. 연속되는 .을 하나의 .으로 치환
4. .가 처음이나 끝에 있다면 제거
5. 빈 문자열이라면 a 를 추가
6. 16자 이상이라면 앞에 15자를 제외한 나머지 문자 제거
7. 2자 이하라면 3자가 될 때까지 마지막 문자를 반복해서 끝에 추가

1단계는 toLowerCase() 를 사용해서 쉽게 할 수 있었다.

2단계에서 처음으로 정규표현을 사용하였다.
정규표현하는 것에도 순서가 있는지 어떻게 하면 맞게 제거되고 어떻게 하면 제거가 되지 않았다.
한 번에 바꾸기 위해 replaceAll() 을 사용하였다.
알파벳과 숫자, -, _, .이 나올 수 있게
["\W|^.-_"] 이렇게 작성을 하였다... 정규표현식을 사용하는 법에 익숙하지 않아 어떤 식으로 사용해야할 지 몰랐다.
이렇게 사용하게 될 경우 맞게 제거되지 않았다.
\W 를 사용하지 않고 범위를 이용하였다.

replaceAll("[^a-z0-9_.-]", "")

이렇게 작성하니 정규표현식이 맞게 적용이 되었다.

나머지 단계들을 문제없이 해결하였지만

"=.=" 이라는 문자열이 들어갈 경우... 오류가 났다..

4단계는

if (new_id.charAt(0) == '.') new_id = new_id.substring(1);
if (new_id.charAt(new_id.length() - 1) == '.') new_id = new_id.substring(0, 	new_id.length() - 1);

이렇게 만들었다.

하지만 "=.=" 이 들어갈 경우 "=" 는 제거되고 "." 만 남는다.

여기서 "." 문자열의 길이는 1.

if (new_id.charAt(new_id.length() - 1) == '.') new_id = new_id.substring(0, 	new_id.length() - 1);

에서

new_id = new_id.substring(0, 	new_id.length() - 1);

부분이 오류가 났다. 길이가 1인 문자열일 때,

new_id = new_id.substring(0, 1 - 1);  // new_id.substring(0, 0)

이렇게 된다.
substrin(0, 0) 는 할 수 없다. 0 번째부터 0개를 자르는 것은 말이 안된다.

그래서

if (new_id.equals(".")) {
	new_id = "";
}

을 추가하여 "." 일 때는 빈 배열로 만들어주었다.
첫 번째로 나오는 "." 는 제거해야하는 규칙이 있기 때문이다.

이렇게 반례를 해결하였다.


알게 된 점

  • 대문자와 소문자가 있는 배열이나, 문자열을 내림차순으로 정렬할 경우 자동으로 대문자가 더 큰 값으로 취급된다.

  • 문제에 적용하지는 않았지만 에라토스테네스의 체의 원리(알고리즘)를 알게 되었다.

  • 아예 몰라던 정규표현식을 어떨 때, 어떻게 사용하는지 조금 알게 되었다.
    [] : 범위표현 '-'로 표현가능하다

profile
💻🌾시골소녀의 엉망징창 개발 성장일지🌾💻 (2023.05.23 ~)

0개의 댓글