문제 : 

 

 

문제는 입력값으로 여러개의 이메일 주소가 주어지면, @를 기준으로 로컬, 도메인 주소로 이메일 주소가 나뉜다. 예를들어, jghdg@naver.com이면, jghdg는 로컬주소, naver.com은 도메인 주소이다. 이때, 로컬 주소에는 다음과 같은 규칙이 따른다.

 

  • ' . '은 무시된다. 예를들어, jghdg.1234@naver.com이라면, ' . '은 무시되므로 jghdg1234@naver.com과 같다.
  • '+'뒤의 문자열들은 모두 무시된다. 예를들어, jghdg+1234@naver.com이라면, jghdg@naver.com이 된다.(도메인은 그대로이다.) 

이때, 실제 이메일을 받을 수 있는 서로 다른 이메일 주소의 갯수를 리턴하라.

 

 

아래는 내가 제출해 통과한 코드이다.

class Solution:
    def numUniqueEmails(self, emails: List[str]) -> int:

        result = set()
        
        for email in emails:
            local_domain = list(email.split('@'))
            local = local_domain[0]
            domain = local_domain[1]

            revised_local = local.replace('.', '')
            plus_idx = revised_local.find('+')
            if plus_idx != -1:
                revised_local2 = revised_local[0:plus_idx]
            else:
                revised_local2 = revised_local
            

            final_addy = revised_local2  + "@" + domain
            result.add(final_addy)

        return len(result)

 

- 먼저, 여기서 결과를 집합으로 선언한 이유는 다음과 같다 : 모든 조건을 적용했을때('.'은 무시되고, '+'뒤의 문자열들은 무시될 때), 우리는 '중복되지 않는' 이메일 주소의 갯수를 구하면 된다. 그렇다면, 규칙을 적용해 새로운 이메일 주소를 만들고, 그 이메일 주소를 집합에 넣어주면 자동으로 중복된 값은 두번 이상 들어가지 않기 때문에 곧바로 집합의 크기를 리턴 하도록 집합을 선언 해 주었다.

 

- 다음으로 for email in emails를 통해 입력값으로 주어진 이메일들을 담은 리스트를 순회한다

    - 여기서 도메인과 로컬 주소를 나눠준다. local_domain은 현재 순회중인 email을 '@'를 기준으로 나눈 후, 각각 배열에 담는다. 이렇           게 되면, 배열의 0번째 인덱스에는 로컬 주소가 담길 것이고, 1번째 인덱스에는 도메인 주소가 담길 것이다. 그래서 local과 domain변         수에 각각 도메인과 로컬 주소를 담아 주었다.


- 이제 도메인과 로컬 주소를 나눠 각각 domain, local이라는 변수에 담아 주었다. 이제, 위에서 설명한 규칙을 로컬 주소에 적용할 차례이다. 로컬에 .replace(' . ', '')를 호출하여 .이 나타나는곳을 '' 즉, 빈 문자열로 바꿔준다. 여기서 ''를 하면 공백이 되는것이 아니라 그냥 .이 나타나는곳이 없어진다. 만약, . 이 나타나는곳을 실제 공백으로 바꾸고 싶다면, replace(' . ',  ' ')를 하면 된다. ('' 대신 가운데 한칸 띄워진 ' ' 가 들어갔다.) 이 단계를 마치면, 이제 이메일 문자열의 .는 모두 없어진 상태이다.

 

- 다음으로 두번째 조건인 + 뒤의 문자열들을 모두 무시하는 코드를 보자. 먼저, + 기호가 없을때는 .index()를 호출하면 런타임 에러가 발생하므로(예외 처리를 해도 되지만 코드가 복잡해진다), .find('+')를 이용해 문자열에 +가 등장하는지 먼저 찾아준다. 파이썬의  .find 메서드는 +를 찾으면 그 인덱스를 반환하고, 찾지 못하면 -1을 반환한다. .index()는 부분 문자열이 존재하지 않으면 예외를 발생시키므로, 예외 처리를 하지 않으면 프로그램이 중단될 수 있다. find()는 부분 문자열이 존재하지 않으면 -1을 반환하므로, 조건문을 사용하여 부분 문자열의 존재 여부를 쉽게 확인할 수 있다.

 

- 만약, .find()를 호출한 결과가 -1이 아니라면, 즉, 문자열 내에 +가 존재한다면, 문자열 슬라이싱을 이용해 +가 나타나는 인덱스의 전까지 revised_local2 라는 변수에 담아주고, 만약 문자열에 +가 나타나지 않는다면 revised_local2에 원래 revised_local을 할당해 그대로 사용한다.

 

이제, 로컬 주소의 모든 룰을 적용 했으므로, 로컬과 도메인을 다시 합쳐 이메일 주소를 만든다. 그 후, 맨 처음 선언한 결과 집합에 이 이메일들을 for문을 돌며 차례로 넣어주면, 중복되지 않는 이메일 주소들이 담길 것이고, 결과적으로 이 집합의 크기를 반환한다.

 

여기서 중요한 내용들은 

- 중복되지 않는 이메일 주소 찾기 :  집합 이용

- .find()메서드는 .index()보다 편리하다(예외처리 대신 -1의 케이스를 처리해주면 됨)

- 문자열 슬라이싱

 

아래는 내가 받은 report이다.

 

 

아래는 GPT를 통해 최적화 시킨 코드이다.

class Solution:
    def numUniqueEmails(self, emails: List[str]) -> int:
        result = set()
        
        for email in emails:
            local, domain = email.split('@')
            local = local.split('+')[0].replace('.', '')
            result.add(local + '@' + domain)

        return len(result)


최적화된 부분 설명

1. `split()` 메서드 최적화:
   - `email.split('@')` 결과를 변수 `local`과 `domain`에 직접 할당하여 리스트 인덱싱을 없앴습니다.
   - `local.split('+')[0]`를 사용하여 '+' 이전의 문자열을 한 번에 추출하고, 이후에 '.'을 제거했습니다.

2. 불필요한 변수 제거:
   - `revised_local2`라는 중간 변수를 제거하고, 바로 `local` 변수에 필요한 값을 할당했습니다.

3. 간결한 문자열 조작:
   - 문자열 조작을 간단하게 하기 위해 한 줄로 처리했습니다.

최적화된 코드의 흐름

1. 이메일을 '@'로 분리하여 `local`과 `domain`으로 나눕니다.
2. `local`을 '+'로 분리하여 '+' 이전의 문자열만 사용하고, '.'을 제거합니다.
3. 최종 이메일 주소를 `local`과 `domain`을 결합하여 만듭니다.
4. `result` 세트에 최종 이메일 주소를 추가합니다.
5. 세트의 크기를 반환하여 고유한 이메일 주소의 수를 계산합니다.

이 최적화된 코드는 더 간결하고 효율적으로 이메일 주소를 처리하여 고유한 이메일 주소의 수를 계산합니다.

+ Recent posts