단골 면접 질문 - 고유한 문자로 이루어진 가장 긴 부분 문자열 찾기 방법

단골 면접 질문 - 고유한 문자로 이루어진 가장 긴 부분 문자열 찾기 방법
It SharingPosted On Jul 23, 20247 min read

저는 전에 만난 진짜 코딩 면접 문제에 대해 이야기하려고 해요.

주어진 문자열 abaabcabaaax 와 같이 문자열이 있다면, 오직 고유한 문자만 포함하는 가장 긴 부분 문자열의 길이를 찾아야 합니다.

  • 가장 긴 부분 문자열은 abc 또는 bca 또는 cab 중 하나입니다.
  • 우리는 길이에만 관심이 있으며, 그 길이는 3입니다.

당신을 위한 몇 가지 테스트 케이스

def longest_substring_length(string: str) -> int:
    """
    구현해야 함
    """

testcases = [
    ('', 0),
    ('a', 1),
    ('aa', 1),
    ('aaa', 1),
    ('aaabbb', 2),
    ('ababababbababa', 2),
    ('aabbccddeeffgg', 2),
    ('aaaaaaabbbbbbbbcccc', 2),
    ('abaaaabcabaaax', 3),
    ('abcbabcababcacbacab', 3),
    ('abababcdbbcc', 4),
    ('abcdcbabcdcba', 4),
    ('bbbabcdeabcdeddd', 5),
    ('abcdef', 6)
]

for string, answer in testcases:
    guess = longest_substring_length(string)
    print(string, answer, guess)

이것을 시도하는 데 시간을 내어주세요!!

잠시 멈춤

최근 Python, 프로그래밍, 그리고 많은 사람들이 알지 못하는 Python 관련 랜덤 팩트에 대한 Substack 뉴스레터를 시작했어요. 함께해요!

제 Substack: https://zlliu.substack.com

또한 최근에 책 101 Things I Never Knew About Python을 썼어요. 제가 더 이른 시기부터 배울 수 있었을 Python 관련 이야기들을 자세히 다루었어요.

여기서 확인해보세요: https://payhip.com/b/vywcf

이 문제를 해결하는 일반적인 아이디어

이 문제를 O(n)의 선형 시간으로 해결해 봅시다.

그리고 O(n)의 시간으로 이 문제를 해결하기 위해서는 문자열을 왼쪽에서 오른쪽으로 순회해야 합니다.

  • left 포인트 left와 right 포인터 right를 유지합니다
  • right - left + 1은 가장 긴 부분 문자열의 길이입니다
  • 각 반복마다, left와 right를 업데이트하고, 가장 긴 길이를 추적합니다.

표의 태그를 Markdown 형식으로 변경해 주세요.

아래의 표 태그를 Markdown 형식으로 변경하세요.

image

이제 문자가 반복됩니다. 우리의 부분 문자열은 aba로, 이는 잘못된 부분 문자열입니다.

  • 사전에서 a의 값을 업데이트합니다.
  • 가능하다면 마지막 a의 앞에있는 문자를 가리키는 left를 증가시킵니다.

image

다음으로, 우리는 오른쪽을 다시 1만큼 증가시킵니다:

image

그리고 다시 다른 'a'를 발견합니다. 이제 우리의 사전과 왼쪽을 업데이트할 때입니다.

image

다음으로, 다시 오른쪽으로 1씩 증가합니다:

이제 우리가 또 다른 b를 만나게 됩니다. 우리의 dict와 left를 업데이트하는 시간입니다.

우리는 b의 값을 4로 업데이트했습니다.

원래는 left를 2로 업데이트하려고 했지만, 이미 left가 그보다 크기 때문에 left를 그대로 두기로 결정했습니다.

다음으로 right를 다시 1 증가시켰습니다:

다음 표식이나 목록을 마크다운 형식으로 전환해주세요.

우리는 또 다른 a를 만났어요.

이제 left와 우리의 딕셔너리를 업데이트해야 해요.

이미지

left는 이제 마지막 a 다음의 b를 가리키고 있어요.

그리고 우리는 사전에서 a의 값을 업데이트합니다.

다음으로, right를 다시 1씩 증가시키겠습니다:

이미지

또 다른 b를 만나게 되었군요. 그리고 나서 left와 우리의 사전을 업데이트합니다.

아래와 같이 Markdown 형식으로 수정해주세요.

다음으로, right를 다시 1씩 증가시켜요:

또 다시 a가 반복돼요. left와 딕셔너리를 다시 업데이트해요

다음으로, 우리는 오른쪽을 다시 1 증가시킬 거에요:

a를 반복해봐요. 우리는 이해하죠. 왼쪽을 업데이트하고 우리의 딕셔너리를 갱신해요

다음으로 오른쪽을 다시 1씩 증가시킵니다:

image1

a. 동일한 작업을 반복합니다. 왼쪽을 업데이트하고 사전을 갱신합니다.

아래 표를 Markdown 형식으로 변경해주세요.

이 과정 동안에 우리는 가능한 가장 긴 부분 문자열의 길이도 추적합니다. 그리고 마지막에 이 값을 반환합시다.

코드 솔루션

def longest_substring_length(string: str) -> int:

    # 만약 문자열의 길이가 0이거나 1이라면, 답을 반환하세요
    if len(string) <= 1:
        return len(string)

    # 우리의 딕셔너리를 초기화합니다
    d = {string[0]:0}

    # 왼쪽과 오른쪽 포인터를 설정합니다
    l = r = 0

    # 이 변수는 유효한 부분 문자열의 가장 긴 길이를 추적합니다
    largest = 0

    while True:
        # 오른쪽을 1씩 증가시킵니다
        r += 1
    
        # 만약 범위를 벗어나면, 종료합니다
        if r >= len(string): break

        # 현재 문자를 추출합니다
        ch = string[r]

        
        if ch not in d:
            # 만약 우리의 딕셔너리에 없는 새로운 문자를 만나면
            d[ch] = r
        else:
            # 반복된 문자를 만나면
            l = max(d[ch] + 1, l)
            d[ch] = r

        # 가장 긴 부분 문자열을 추적합니다
        if largest < r-l+1:
            largest = r-l+1

    return largest

testcases = [
    ('', 0),
    ('a', 1),
    ('aa', 1),
    ('aaa', 1),
    ('aaabbb', 2),
    ('ababababbababa', 2),
    ('aabbccddeeffgg', 2),
    ('aaaaaaabbbbbbbbcccc', 2),
    ('abaaaabcabaaax', 3),
    ('abcbabcababcacbacab', 3),
    ('abababcdbbcc', 4),
    ('abcdcbabcdcba', 4),
    ('bbbabcdeabcdeddd', 5),
    ('abcdef', 6)
]

for string, answer in testcases:
    guess = longest_substring_length(string)
    print(string, answer, guess)

결과:

 0 0
a 1 1
aa 1 1
aaa 1 1
aaabbb 2 2
ababababbababa 2 2
aabbccddeeffgg 2 2
aaaaaaabbbbbbbbcccc 2 2
abaaaabcabaaax 3 3
abcbabcababcacbacab 3 3
abababcdbbcc 4 4
abcdcbabcdcba 4 4
bbbabcdeabcdeddd 5 5
abcdef 6 6

결론

이해하기 쉽고 명확했으면 좋겠습니다.

만약 크리에이터로서 저를 지원하고 싶다면

  • 제 Substack 뉴스레터에 가입해 주세요. https://zlliu.substack.com/ 에서 확인 가능합니다. 제가 파이썬과 관련된 주간 이메일을 보내드립니다.
  • 제 책인 101 Things I Never Knew About Python을 구매해 보세요. https://payhip.com/b/vywcf 에서 구매 가능합니다.
  • 이 이야기에 대해 50번 박수를 치세요.
  • 여러분의 생각을 나에게 말씀해 주세요. 댓글을 달아주세요.
  • 이 이야기 중 마음에 드는 부분을 강조해 주세요.

감사합니다! 이런 작은 행동들이 큰 힘이 됩니다. 정말 감사드립니다!

YouTube: https://www.youtube.com/@zlliu246

LinkedIn: https://www.linkedin.com/in/zlliu/