[Leet Code] Valid Number

기면지·2021년 5월 16일
0

LeetCode

목록 보기
7/20
post-thumbnail

안녕하세요!
오늘은 5월 3주차 첫번째 알고리즘인 Valid Number 풀이를 적어보겠습니다.


문제


요약
주어진 문자열 s 가 유효한 Integer 또는 Decimal 인지 확인하여 true , false 를 return하는 문제입니다.

처음 시도한 방법

. , e 를 포함하면 그것을 기준으로 앞, 뒤로 문자열을 나눈 후 앞과 뒤의 문자열의 유효성을 검사해주었습니다.

하지만.. 경우의 수가 너무너무 많았고 저는 자바가 저보다 똑똑한 것을 3시간만에 알아차렸습니다.

두번째로 시도한 방법

3시간동안 삽질을하다가 Double 자료형에 parseDouble 이라는 아주 멋진 함수가 있다는 것을 알게됩니다.
Double.parseDouble(s) 로 모든 경우의 유효성 검사가 가능했고, infinity 인 경우만 필터링해주면 되었습니다. Accept 를 받았죠.

하지만.. 알고리즘을 푸는 이유는 내장 함수를 최대한 안쓰기 위함 아니겠습니까..?
그래서 눈물을 머금고 다시 생각해봤습니다.

세번째로 시도한 방법

최근에 세번째까지 온 문제가 드물었는데, 이 문제는 어려웠습니다.. 🥲

s 의 앞 / 뒤에 공백이 있는 경우도 있기 때문에, trim() 을 사용해서 앞 / 뒤 공백을 지워준 후 dot , digit , expboolean 변수를 설정해 맨 처음부터 유효성 검사를 해주었습니다.

정말 오래 시간을 소요해서 드디어 로직을 짜고 Accept 를 받았습니다.
이제부터는 로직을 조금 더 자세하게 설명하겠습니다.

코드 설명

String string = s.toLowerCase().trim();
boolean dot = false, exp = false, digit = false;

s 가 대문자가 포함되어있는 경우도 있기 때문에, toLowerCase() 로 소문자로 변경해주고 trim() 을 사용해 앞 / 뒤의 공백을 제거했습니다.
그리고 . 이 나타나는 것을 체크하는 dot , e 가 나타나는 것을 체크하는 exp , 숫자가 나타나는 것을 체크하는 digit 변수를 설정합니다.

for (int i = 0; i < string.length(); i++) {
    char c = string.charAt(i);
    // ...
}

문자열의 처음부터 유효성 검사를 할 것이기 때문에 for문을 순회합니다.
그리고 해당 위치에 해당하는 문자를 c 에 저장합니다.

if (Character.isDigit(c)) digit = true;

c 가 숫자인 경우에 digittrue 로 설정합니다.

else if (c == '.') {
    if (exp || dot) return false;
    dot = true;
}

c. 인 경우는 소수인 경우입니다.
문제에서 eInteger 로 취급한다고 했기 때문에 etrue 라면 유효하지 않는 문자열이고, 한 문자열에 . 가 여러개 있어도 유효하지 않는 문자열입니다.

때문에 해당 경우에 false 를 return 하고 조건에 해당하지 않는다면 dottrue 로 설정합니다.

else if (c == 'e') {
    if (exp || digit == false) return false;
    exp = true;
    digit = false;
}

ce 인 경우는 정수인 경우입니다.
그리고 e 표기법인 경우에는 e 의 앞 / 뒤에 모두 숫자가 포함되어야하기 때문에 digitfalse 라면 유효하지 않는 문자열입니다.
e 가 여러번 나와도 유효하지 않습니다.

e. 이 표시되는 경우도 있기 때문에 dot 는 조건에 없습니다.

조건을 체크한 후에 유효하지 않는 조건에 해당되지 않는다면 exptrue 로 설정하고, digitfalse 로 설정합니다.
왜냐하면 e 뒷부분에 + / - / . 들이 나와도 유효하기 때문에 초기화해주는 것입니다.

else if (c == '+' || c == '-') {
    if (i > 0 && string.charAt(i - 1) != 'e') return false;
}

c 가 연산자일 경우는 해당 문자 앞에 e 가 있거나 문자열의 가장 처음에만 가능합니다.

따라서 조건에 맞다면 false 를 return 하고, 따로 체크는 해주지 않아도 됩니다.

else return false;

위의 조건들에 모두 해당하지 않는다면 유효하지 않은 알파벳이 포함되어있는 것이므로 false 를 return 합니다.

전체 코드

class Solution {
    public boolean isNumber(String s) {
        String string = s.toLowerCase().trim();
        boolean dot = false, exp = false, digit = false;

        for (int i = 0; i < string.length(); i++) {
            char c = string.charAt(i);
            if (Character.isDigit(c)) digit = true;
            else if (c == '.') {
                if (exp || dot) return false;
                dot = true;
            }
            else if (c == 'e') {
                if (exp || digit == false) return false;
                exp = true;
                digit = false;
            }
            else if (c == '+' || c == '-') {
                if (i > 0 && string.charAt(i - 1) != 'e') return false;
            }
            else return false;
        }

        return digit;
    }
}

마무리

약 5시간동안 알고리즘을 푼 것 같은데요.
다 풀고 나니까 뿌듯합니다!
저는 이제 알고리즘에 시간을 소요하느라 못한 나머지 공부를 지금 하러가야겠습니다.

이번 포스팅도 읽어주셔서 감사합니다 :)

profile
𝙎𝙈𝘼𝙇𝙇 𝙎𝙏𝙀𝙋𝙎 𝙀𝙑𝙀𝙍𝙔 𝘿𝘼𝙔

0개의 댓글