문제 :
문제는 입력값으로 여러개의 이메일 주소가 주어지면, @를 기준으로 로컬, 도메인 주소로 이메일 주소가 나뉜다. 예를들어, 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. 세트의 크기를 반환하여 고유한 이메일 주소의 수를 계산합니다.
이 최적화된 코드는 더 간결하고 효율적으로 이메일 주소를 처리하여 고유한 이메일 주소의 수를 계산합니다.
'CodingTest > Leetcode' 카테고리의 다른 글
[LeetCode] 125.Valid Palindrome (0) | 2024.07.04 |
---|---|
[LeetCode] 961. N-Repeated Element in Size 2N Array (0) | 2024.07.03 |
[LeetCode] #884. Uncommon Words from Two Sentences (0) | 2024.07.02 |
[LeetCode] #819. Most Common Word (0) | 2024.06.28 |
[LeetCode] #804. Unique Morse Code Words (0) | 2024.06.27 |