Data Structure and Algorithm/코딩테스트준비

leetcode 961. N-Repeated Element in Size 2N Array 솔루션

Razelo 2022. 6. 15. 10:36

이 문제는 어려운 문제가 아니다. 굉장히 쉬운 문제다. 그냥 지문 그대로 옮겨서 구현만 하면 되는 문제다. 

 

그런데 문제를 풀어낸 솔루션에서 굉장히 재미난 동작을 발견했다. 파이썬 언어차원에서의 동작인것 같은데 처음에는 왜 이렇게 동작하나 의아했는데 꽤나 재밌다는 생각이 들어서 따로 뽑아서 블로그에 정리하고자 한다. 우선 문제 링크는 아래와 같다. 슥 봐도 쉬운 문제임을 알 수 있을 것이다. 

https://leetcode.com/problems/n-repeated-element-in-size-2n-array/

 

그런데 중요한건 문제를 어떻게 풀었냐가 아니다. 문제를 풀어낸 과정에서의 코드 몇줄에서 발생한 신기한 동작이다. 

내 솔루션은 아래와 같다. 

 

from collections import defaultdict 
class Solution:
    def repeatedNTimes(self, nums: List[int]) -> int:
        # 길이는 2의 배수 
        # n + 1개의 unique 한 요소 가지고 있음. 
        # 정확히 한개의 요소만 n번 반복해서 등장함. 
        n = len(nums)//2 
        d = defaultdict(int)
        for num in nums:
            d[num] += 1
        for k, v in d.items():
            if v == n:
                return k

 

자 평범한 솔루션이다. 여기서 뭐가 이상하다는 걸까? 코드를 보면 for문에서 nums에서 num을 하나씩 뽑으면서 d[num]으로 1씩 증가시켜주는 코드가 중간에 보일 것이다. 과연 여기서 반복변수로 num 이 아니라 n 을 쓴다면 어떤 동작이 발생할까? 

 

즉 아래처럼 말이다. 

from collections import defaultdict 
class Solution:
    def repeatedNTimes(self, nums: List[int]) -> int:
        # 길이는 2의 배수 
        # n + 1개의 unique 한 요소 가지고 있음. 
        # 정확히 한개의 요소만 n번 반복해서 등장함. 
        n = len(nums)//2 
        d = defaultdict(int)
        for n in nums:
            d[n] += 1
        for k, v in d.items():
            if v == n:
                return k

 

당연히 문제없이 동작할 것이라고 생각했다. 왜냐면 for문에서 반복변수로 사용하는 n은 for문 스코프 밖의 영역에는 영향을 주지 않을 것이라고 생각했기 때문이다. 그러나 위 코드는 오답으로 처리된다. 그것도 None을 리턴한다. 왜 이런 동작이 발생하는 걸까 추측해보았다. 왜 이럴까? 나름의 추측을 해보았다. 

 

아마 for문 위에서 선언한 n = len(nums)//2 에서 n 변수가 할당된 location 을 아래 코드의 for문에서 반복 변수 n이 쓰이면서 해당 location을 덮어씌우는 동작을 하는 것 같다. 

 

물론 해결 방법은 존재한다. 임시방책이긴 하지만, 

n  = len(nums)// 2 <- 이 코드를 for 문보다 아래에 적어주면 될 것이다. 

더 확실하게 하고 싶다면? 그냥 for문이라고 해도 위에 선언된 변수와 네이밍이 겹치는 변수를 for의 반복변수로 설정하지 않으면 된다. 

 

그런데 이런 동작은 왠지 처음 보는 것 같다. 자바나 C에서 이런 동작이 없었던것 같은데 파이썬에서는 for문에서의 반복 변수가 for 스코프 밖 변수의 메모리 셀을 건드리는 것 같다. 즉 우선적으로 스코프를 추적해서 변수를 잡는게 아니라 실제 변수 네이밍을 추적해서 변수를 잡는게 스코프보다 우선되는 것 같다. 물론 함수인 경우에는 제외인것 같다. 아마 내부적으로 다른 언어들과 미세한 동작 차이가 있는듯하다. 

 

오랜만에 심심했는데 꽤나 재미난 동작을 보게 되어서 좋았다. 

 

 

반응형