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이라는 값이 나오기 때문에 접근하기 어려웠다. 우선 차근히 생각해보면,
테스트 케이스가 정말 좋게 말하면 다양한(ㅎㅎ) 문제였다...
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' 와 같이 사용하는 방법이다... 까먹지 말아야지...