정렬된 숫자 리스트가 주어졌을 때, 해당 숫자 범위 안에서 빠져 있는 숫자들을 찾아야 하는 경우가 자주 있습니다. 예를 들어 [1, 5, 6, 7, 11, 14]라는 리스트가 있다면, 1부터 14 사이에 존재하지 않는 숫자들이 무엇인지 확인하는 것이죠.
이번 글에서는 파이썬으로 이 문제를 해결하는 두 가지 대표적인 방법을 소개합니다.
방법 1: range 함수 활용
리스트의 첫 번째 요소부터 마지막 요소까지의 범위를 range()로 생성한 뒤, for 루프를 돌면서 각 숫자가 리스트에 포함되어 있는지 not in 연산자로 검사하는 방식입니다.
리스트 컴프리헨션(list comprehension)을 사용하면 코드를 간결하게 작성할 수 있습니다.
예제 코드
listA = [1,5,6,7,11,14]
# 원본 리스트 출력
print("주어진 리스트 : ", listA)
# range를 이용해 누락된 숫자 찾기
res = [x for x in range(listA[0], listA[-1]+1)
if x not in listA]
# 결과 출력
print("누락된 숫자들 : \n", res)실행 결과
주어진 리스트 : [1, 5, 6, 7, 11, 14] 누락된 숫자들 : [2, 3, 4, 8, 9, 10, 12, 13]
방법 2: zip 함수 활용
두 번째 방법은 zip() 함수를 사용해 인접한 두 요소를 짝지어 비교하는 방식입니다. 리스트 전체와 리스트의 두 번째 요소부터 끝까지를 zip으로 묶으면, 연속된 숫자 쌍(앞 값 m과 뒤 값 n)을 얻을 수 있습니다.
이때 두 값의 차이가 1보다 크다면 그 사이에 누락된 숫자가 있다는 뜻이므로, m+1부터 n-1까지의 숫자를 결과에 추가하면 됩니다.
예제 코드
listA = [1,5,6,7,11,14]
# 원본 리스트 출력
print("주어진 리스트 : ", listA)
# zip을 이용해 누락된 숫자 찾기
res = []
for m, n in zip(listA, listA[1:]):
if n - m > 1:
for i in range(m+1, n):
res.append(i)
# 결과 출력
print("누락된 숫자들 : \n", res)실행 결과
주어진 리스트 : [1, 5, 6, 7, 11, 14] 누락된 숫자들 : [2, 3, 4, 8, 9, 10, 12, 13]
두 방법의 비교
range 방식은 코드가 직관적이라 이해하기 쉽지만, 리스트의 모든 요소를 반복해서 검사하기 때문에 리스트가 길어질수록 시간 복잡도가 O(n²)로 증가할 수 있습니다.
반면 zip 방식은 이미 정렬된 리스트에서 인접한 요소만 비교하므로 효율적이며, 특히 데이터 크기가 클 때 유리합니다. 다만 리스트가 반드시 오름차순으로 정렬되어 있어야 올바른 결과를 얻을 수 있다는 점에 유의하세요.