[LeetCode] atoi (JS)

nRecode·2021년 1월 4일
1

Algorithm

목록 보기
22/48

문제

Implement atoi which converts a string to an integer.

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

If no valid conversion could be performed, a zero value is returned.

note
Only the space character ' ' is considered a whitespace character.
Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. If the numerical value is out of the range of representable values, 231 − 1 or −231 is returned.

입출력 예
Input: str = " -42"
Output: -42

Input: str = "4193 with words"
Output: 4193

Input: str = "words and 987"
Output: 0

Input: str = "-91283472332"
Output: -2147483648

접근

이 문제는 문자열을 정수로 return하는 문제인데, -나 +의 경우 Number로 변환을 시도해도 NaN이라는 값이 나오기 때문에 접근하기 어려웠다. 우선 차근히 생각해보면,

  1. 공백을 제거한다. -> trim()을 사용한다.
  2. s를 순회하면서 숫자인 경우에만 추가하고 문자가 나오면 종료한다. (단, '-','+'부호를 주의해야 함)
  3. 변수가 32 비트 INT 범위 내인지 판단을 하고 아니면 -2147483648나 2147483647 리턴 -> 이와 관련된 메소드가 있는가?
  4. 숫자로 변환할 수 없는 경우 0 return.
  5. s[i]가 공백인 경우도 문자로 처리

풀이

테스트 케이스가 정말 좋게 말하면 다양한(ㅎㅎ) 문제였다...
ex) '-+12' => return 0, '- 34' => return 0, '0000023' => return 23 등등
분기태우는 연습을 하는 것이라고 생각하고 열심히 해보려 했는데 하드코딩 마저도 성공하지 못했다...

var myAtoi = function(s) {  
    s = s.trim();
    let resultString = '';
    
    // 시작이 부호도 아니고 문자도 아닌것
    if(s[0] !== '+' && s[0] !== '-' && !Number(s[0]) && !(Number(s[0]) === 0)) return 0;
    // 두번 연속 문자인경우(위에서 문자는 걸러지므로 '-+'나 '+-'의 경우)
    if(!Number(s[0]) && !(Number(s[0]) === 0) && !(Number(s[1]) === 0) && !Number(s[1])) return 0;
    
    // 시작은 숫자 아니면 부호만 남았음
    resultString = resultString + s[0];
    
    // 숫자와 문자 분류하여 분기
    for(let i = 1; i < s.length; i++){
        if(s[i] === ' '){
            break;
        }else if(Number(s[i]) || Number(s[i]) === 0){
            resultString += s[i];
            console.log(resultString)
        }else{
         break;   
        }
    } 
  
    if( (Number(resultString) <= Math.pow(2,31) - 1) && (-Math.pow(2,31) <= Number(resultString)) ){
        return Number(resultString);
    }else if(-Math.pow(2,31) > Number(resultString)){
        return -Math.pow(2,31);
    }else{
        return Math.pow(2,31) - 1;
    }
}

위 코드는 웬만한 테케는 통과를 하지만 부호 하나뒤 바로 문자나 공백이 나오면 테스트를 통과하지 못했다...
" - 42"를 input 했을때 resultString은 '-'가 되며, return은 어디에도 속하지 않으므로 Math.pow(2,31) - 1이다.

해결 방법

해결방법은
1. 기본적으로 return 하는 변수 resultNum와 i를 0으로 선언하고 부호를 결정하는 변수 sign에 1을 선언한다.
2. 다음 trim()을 사용하지 않고 while을 이용하여 i를 공백만큼 ++한다.
3. 그 후의 s[i]는 부호이거나 숫자로 바꿀 수 있는 문자이거나 그냥 문자일텐데, 부호라면 '-'일 땐 sign을 -1로 '+'일 땐 그대로해서 i++한다.
4. while을 이용하여 s[i] >= '0' && s[i] <= '9'일 동안 반복하는데 기존의 resultNum에 10을 곱하고 + s[i++]를 한다. 또 이때 INT범위를 충족하는지 검사한다.
5. return resultNum * sign;

var myAtoi = function(s) {
   // 1
    let sign = 1;
    let i = 0;
    let resultNum = 0;
    // 2
    while(s[i] === ' '){
        i++;
    }
  // 3
    if(s[i] === '-' || s[i] === '+'){
        if(s[i] === '-') sign = -1
        i++;
    }
    // 4
    while(s[i] >= '0' && s[i] <= '9'){
        // s[i] - '0' -> 문자열을 정수로 변환시켜줌
        resultNum = resultNum * 10 + (s[i++] - '0')
        // INT범위를 충족하는지 검사
        if( sign === -1 && Math.pow(2,31) < resultNum){
            return -Math.pow(2,31);
        }
        if(sign === 1 && Math.pow(2,31) - 1 < resultNum){
            return Math.pow(2,31) - 1;
        }    
    }
    // 5
    return resultNum * sign;

};

이 방법을 토대로 해결하지 못한 첫번째 방법에 부호변수를 추가해서 설계하면 통과도 가능하다.
놓쳤던 점은 Number로 형 변환을 하지 않아도 s[i] >= '0' && s[i] <= '9' 와 같이 사용하는 방법이다... 까먹지 말아야지...

profile
안정성, 확장성 있는 서버를 구축하고 가꾸는 개발자를 목표로 공부하고 있습니다. 🤔🤔🤔🤔 부족하기에 맞지 않는 내용이 있을 수 있습니다. 가감없이 피드백 해주시면 정말 감사하겠습니다..🙏

0개의 댓글