Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python으로 리스트의 중복 요소를 찾아 마지막 등장 항목만 삭제하는 방법


문제 개요

숫자로 이루어진 리스트 A가 주어졌을 때, 리스트 안의 모든 중복 숫자를 찾아낸 뒤 각 숫자의 마지막으로 등장한 항목만 제거하는 프로그램을 만들어 보겠습니다.

예를 들어 입력이 [10, 30, 40, 10, 30, 50]이라면, 10과 30이 각각 두 번씩 등장합니다. 따라서 마지막에 등장한 10과 30을 제거한 결과인 [10, 30, 40, 50]이 출력됩니다.

해결 접근 방식

핵심 아이디어는 딕셔너리(맵) 두 개를 활용하는 것입니다.

  • d: 각 숫자가 리스트 전체에서 몇 번 등장하는지 저장하는 맵
  • seen: 왼쪽부터 순회하면서 지금까지 몇 번 마주쳤는지 기록하는 맵

전체 진행 단계는 다음과 같습니다.

  1. 첫 번째 순회에서 각 숫자의 총 등장 횟수를 d에 기록합니다.
  2. 두 번째 순회에서 현재 원소의 총 횟수 n을 확인하고, seen에 지금까지 본 횟수를 누적합니다.
  3. 현재까지 본 횟수가 총 횟수와 같고(n == seen[nums[i]]) 그 값이 1보다 크다면, 해당 원소가 이 숫자의 마지막 등장이므로 리스트에서 삭제합니다.
  4. 삭제하면 뒤의 요소들이 한 칸씩 앞으로 당겨지므로 인덱스 i를 1 감소시켜 다음 원소를 건너뛰지 않도록 합니다.
  5. 모든 순회가 끝나면 수정된 리스트를 반환합니다.

구현 코드

class Solution:
   def solve(self, nums):
      seen = {}
      d = {}
      # 1단계: 각 숫자의 총 등장 횟수 계산
      for i in range(len(nums)):
         if nums[i] not in d:
            d[nums[i]] = 1
         else:
            d[nums[i]] += 1

      # 2단계: 마지막 등장 항목 제거
      i = 0
      while i < len(nums):
         n = d[nums[i]]
         if nums[i] not in seen:
            seen[nums[i]] = 1
         else:
            seen[nums[i]] += 1

         # 마지막 등장이면서 중복인 경우 삭제
         if n == seen[nums[i]] and n > 1:
            nums.pop(i)
            i -= 1
         i += 1
      return nums

ob = Solution()
print(ob.solve([10, 30, 40, 10, 30, 50]))

입력

[10, 30, 40, 10, 30, 50]

출력

[10, 30, 40, 50]

동작 원리 상세 설명

입력 [10, 30, 40, 10, 30, 50]을 기준으로 코드의 흐름을 살펴보겠습니다.

  • 첫 번째 순회가 끝나면 d{10: 2, 30: 2, 40: 1, 50: 1}이 됩니다.
  • 인덱스 3에 있는 10에 도달하면 seen[10]이 2가 되어 총 횟수 2와 일치하고, 1보다 크므로 삭제 대상이 됩니다.
  • 삭제 후 한 칸 당겨진 자리에 온 30 역시 마지막 등장이므로 같은 방식으로 제거됩니다.
  • 4050은 한 번만 등장했기 때문에(n == 1) 조건을 만족하지 않아 그대로 유지됩니다.

복잡도 분석

  • 시간 복잡도: 리스트를 두 번 순회하므로 탐색 자체는 O(n)입니다. 다만 pop() 호출 시 요소 이동 비용이 발생하므로, 중복이 매우 많은 최악의 경우 O(n²)까지 늘어날 수 있습니다.
  • 공간 복잡도: O(k) — 여기서 k는 서로 다른 숫자의 개수입니다.