LeetCode/Grind169

8. String to Integer (atoi) ☆☆★

hyunkookim 2025. 4. 26. 09:31

8. String to Integer (atoi)

 

지금 문자열을 int로 변환하는 myAtoi 함수를 직접 짜고 있는데,
잘못된 부분이 몇 개 있어서 정확하게 짚어줄게. 👏


❗ 문제점 1 — 부호(+, -) 체크가 잘못됨

if s[i] not in valid:
    break
if s[i] not in op:
    break

이렇게 되면 숫자도 아니고, 부호도 아니면 끊어야 하는데,
네 코드에서는 숫자가 아니기만 해도 바로 break 되어버려.

즉, -42 같은 걸 만나면,

  • -는 숫자가 아니니까 첫 줄에서 바로 break 됨 ❗
  • 실제로는 부호는 받아야 하는데.

✅ 고쳐야 해:

  • 첫 번째 글자부호일 수도 있고, 숫자일 수도 있음
  • 그 이후부터는 숫자만 와야 함

❗ 문제점 2 — if s[i] not in valid와 if s[i] not in op가 독립적으로 있음

지금 두 개를 따로따로 체크하는데, 논리가 이상해져.

  • 숫자가 아닌데도 부호가 아니면 끊어야 하는데,
  • 각각 따로 체크하다 보니까 이상하게 동작해.

❗ 문제점 3 — 부호(-)를 숫자 앞에 매번 붙임

if s[i] == "-":
    integer = f"-{integer}"
  • 근데 이러면 숫자 중간에 -가 나오면 계속 붙어버려 ❗
  • 실제로는 부호는 첫 번째만 체크하면 되고, 그 다음은 무시해야 해.

✅ 제대로 정리하면 로직은 이렇게 돼야 해

  1. 공백을 제거한다 (s.strip()).
  2. 부호를 하나 체크한다 (+ 또는 -).
  3. 숫자를 읽는다 (숫자 아닌 거 나오면 멈춘다).
  4. 숫자가 없으면 0을 리턴한다.
  5. 결과를 int로 변환해서 부호 적용 후 리턴한다.

✨ 제대로 고친 버전

class Solution:
    def myAtoi(self, s: str) -> int:
        s = s.strip()  # 1. 문자열 앞뒤 공백 제거
        
        if not s:
            return 0  # 2. 공백만 있는 경우 0 반환
        
        sign = 1  # 3. 기본 부호는 양수(+)
        idx = 0   # 4. 문자열을 탐색할 인덱스

        # 5. 첫 글자가 부호일 경우 처리
        if s[0] == "-":
            sign = -1  # 음수 부호
            idx = 1    # 다음 문자부터 읽기
        elif s[0] == "+":
            idx = 1    # 양수 부호 (기본값 유지) → 다음 문자부터 읽기

        integer = ""  # 6. 숫자 부분만 저장할 문자열

        # 7. 숫자(0~9)만 읽기
        while idx < len(s) and s[idx].isdigit():
            integer += s[idx]  # 숫자이면 integer 문자열에 추가
            idx += 1           # 다음 문자로 이동

        # 8. 숫자가 하나도 없으면 0 반환
        if integer == "":
            return 0
        
        num = sign * int(integer)  # 9. 부호를 적용해서 정수 변환

        # 10. 32비트 정수 범위 초과/이하 처리
        INT_MAX = 2**31 - 1  # 2147483647
        INT_MIN = -2**31     # -2147483648
        
        if num < INT_MIN:
            return INT_MIN
        if num > INT_MAX:
            return INT_MAX

        # 11. 최종 변환 결과 반환
        return num

🎯 한 문장 요약

"myAtoi는 공백 제거 → 부호 체크 → 숫자만 읽기 → int로 변환 → 32비트 범위로 클램프하는 순서로 짠다."

 

두 번째 내 코드

class Solution:
    def myAtoi(self, s: str) -> int:
        # 첫번째 부호있을수 있음

        l = 0
        sign = 1
        res = ""
        while l<len(s):
            if l==0 and (s[l] == "+" or s[l] == "-"):
                if s[l] == "+":
                    sign = 1
                if s[l] == "-":
                    sign = -1
                l+=1
             if s[l] == " " or s[l].isdigit():
                if s[l].isdigit():
                    res += s[l]
                l+=1
            else:
                break

        if res == "":
            return 0

        res = int(res)*sign
        if res < -2**31:
            res =-2**31
        elif res > 2**31-1:
            res = 2**31-1
        return res

 

조금만 수정하면 완벽해질 것 같아.
지금 네 코드 문제점은 2가지야:


1. if 문 들여쓰기 오류

if l==0 and (s[l] == "+" or s[l] == "-"):
    ...
if s[l] == " " or s[l].isdigit():

여기 두 번째 if가 첫 번째 if 안으로 잘못 들어가 있어.

elif로 연결해야 해.
안 그러면 문법 오류 나.


2. 공백 처리 순서 문제

문자열 맨 앞에 " " (공백)이 여러 개 있을 수 있는데,
지금은 l==0일 때만 부호를 보고, 바로 숫자/공백 검사하는데, 공백을 먼저 다 무시한 다음에 부호랑 숫자를 봐야 해.


✨ 깔끔하게 고친 버전(내 버전)

class Solution:
    def myAtoi(self, s: str) -> int:
        # 첫번째 부호있을수 있음

        l = 0
        sign = 1
        res = ""
        s =s.strip() # 우선 공백 제거

        while l<len(s):
            if l==0 and (s[l] == "+" or s[l] == "-"):
                if s[l] == "+":
                    sign = 1
                if s[l] == "-":
                    sign = -1
                l+=1

            elif s[l].isdigit():
                if s[l].isdigit():
                    res += s[l]
                l+=1
                
            else:
                break

        if res == "":
            return 0

        res = int(res)*sign
        if res < -2**31:
            res =-2**31
        elif res > 2**31-1:
            res = 2**31-1
        return res

 

좀 더 최적화

class Solution:
    def myAtoi(self, s: str) -> int:
        # 첫번째 부호있을수 있음

        l = 0
        sign = 1
        res = ""
        s =s.strip() # 우선 공백 제거

        # 제일 처음에만 + - 부호가 있을 수 있으므로
        # if len(s) >0 and (s[l] == "+" or s[l] == "-"):
        if l< len(s) and (s[l] == "+" or s[l] == "-"):
            if s[l] == "+":
                sign = 1
            if s[l] == "-":
                sign = -1
            l+=1

        """
        while l<len(s):            
            if s[l].isdigit():
                res += s[l]
                l+=1
            else:
                break
        이 코드를 더 최적화 하면, 아래 코드가 됨!!
        """
        while l<len(s) and s[l].isdigit():
            res += s[l]
            l+=1
            
        if res == "":
            return 0

        res = int(res)*sign
        if res < -2**31:
            res =-2**31
        elif res > 2**31-1:
            res = 2**31-1
        return res

✨ 깔끔하게 고친 버전(GPT 버전)

class Solution:
    def myAtoi(self, s: str) -> int:
        l = 0
        sign = 1
        res = ""
        
        # 1. 공백 먼저 무시
        while l < len(s) and s[l] == " ":
            l += 1
        
        # 2. 부호 처리
        if l < len(s) and (s[l] == "+" or s[l] == "-"):
            if s[l] == "-":
                sign = -1
            l += 1
        
        # 3. 숫자 처리
        while l < len(s) and s[l].isdigit():
            res += s[l]
            l += 1
        
        # 4. 숫자 없으면 0 리턴
        if res == "":
            return 0
        
        # 5. 최종 결과 계산
        res = int(res) * sign
        if res < -2**31:
            res = -2**31
        elif res > 2**31-1:
            res = 2**31-1
        
        return res

✅ 요약

  • 공백 무시 → 부호 확인 → 숫자 저장 순서로!
  • if-elif-else 구조 깨지지 않게 깔끔하게!
  • 숫자 없으면 0 리턴하는 것도 잊지 말기!
class Solution:
    def myAtoi(self, s: str) -> int:
        # 첫번째 부호있을수 있음

        l = 0
        sign = 1
        res = ""
        s =s.strip() # 우선 공백 제거

        while l<len(s):
            if l==0 and (s[l] == "+" or s[l] == "-"):
                if s[l] == "+":
                    sign = 1
                if s[l] == "-":
                    sign = -1
                l+=1

            elif s[l].isdigit():
                if s[l].isdigit():
                    res += s[l]
                l+=1
                
            else:
                break

        if res == "":
            return 0

        res = int(res)*sign
        if res < -2**31:
            res =-2**31
        elif res > 2**31-1:
            res = 2**31-1
        return res

 

최종 코드

class Solution:
    def myAtoi(self, s: str) -> int:
        
        # 일단 공백 지우고
        s = s.strip() 
        """
        s가 빈 문자열이면 s[0]이 없으므로 IndexError가 발생
        → s.strip() 후에는 반드시 빈 문자열인지 체크해야 !!
        """
        if not s:
            return 0
        
        # 첫번째 부호 기호인지, 숫자인지 등 체크
        sign = 1
        i=0
        if s[i] == "-":
            sign = -1
            i+=1            
        elif s[i] == "+":
            sign = 1
            i+=1
        
        res = ""
        while i< len(s) and s[i].isdigit():
            res += s[i]
            i+=1

        final_number = int(res)*sign if res != "" else 0
        INT_MAX = 2**31-1
        INT_MIN = -2**31
        if final_number > INT_MAX:
            final_number = INT_MAX
        elif final_number < INT_MIN:
            final_number = INT_MIN        

        return final_number