부트캠프

[5일차] TIL (문자열 다루기)

반응형

알고리즘 주차 시작

알고리즘 강의를 듣고 과제(문자열 조작 / 배열)를 푸는 식 이었습니다.

 

오전 중으로 강의를 다 듣고 8시 발표 전까지 과제를 다 풀어야했고 다음은 과제 내용입니다.

 

1. 그룹 애너그램 

https://leetcode.com/problems/group-anagrams/

처음에는 다음과 같이 이중 for문을 돌려서 비효율적으로 접근 했습니다.

    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        new_strs = []
        temp = []
        for word in strs:
            # sort() vs sorted()
            sort_word = sorted(word)
            sort_word = ''.join(sort_word)  # 알파벳 순으로 정렬
            new_strs.append(sort_word)  # result라는 배열에 저장 []
            if sort_word not in temp:
                temp.append(sort_word)

        # strs = ["eat","tea","tan","ate","nat","bat"]
        # new_strs = ['aet', 'aet', 'ant', 'aet', 'ant', 'abt']
        # temp = ['aet', 'ant', 'abt']

        answer = [[] for _ in range(len(temp))]

        for i in range(len(strs)):
            for j in range(len(temp)):
                if new_strs[i] == temp[j]:
                    answer[j].append(strs[i])

        return answer

 

 

더 효율적인 풀이로는 defaultdict라는 라이브러리를 import 해오면 배열 초기화 없이 배열을 다룰 수 있다는 점이 장점입니다.

from collections import defaultdict
    
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        anagrams = defaultdict(list)
        
        for word in strs:
            # 정렬하여 딕셔너리에 추가
            anagrams[''.join(sorted(word))].append(word)
        print(anagrams)
        return list(anagrams.values())

 

 

2. 가장 긴 팰린드롬 부분 문자열

https://leetcode.com/problems/longest-palindromic-substring/

이 문제를 보고 감조차 잡지 못했습니다.

 

답안지 풀이

def longestPalindrome(s: str) -> str:
    def expand(left: int, right: int) -> str:
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return s[left + 1:right]

    # 해당 사항이 없을 땐 빠르게 리턴
    if len(s) < 2 or s == s[::-1]:
        return s
    result = ''
    for i in range(len(s) - 1):
        result = max(result, expand(i, i + 1), expand(i, i + 2), key=len)
    return result

여기서 expand(i, i + 1)은 짝수개의 글자를 판별하고 expand(i, i + 2) 는 홀수개의 글자를 판별합니다.

 

 

 

3. 세 수의 합

https://leetcode.com/problems/3sum/

저는 우선 3개의 조합으로 된 경우의 수를 뽑아보기로 했습니다. 

뽑고 난 후 각 튜플로 된 원소들을 정렬하고 중복되는 것을 제거하면서 answer라는 리스트에 담았습니다.

 

아래 풀이는 내가 풀었지만 Memory Limit Exceeded

from itertools import combinations

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        data = list(combinations(nums, 3))
        answer = []
        for item in data:
            if sum(item) == 0:
                new_item = tuple(sorted(item, key=lambda x:x))
                if new_item not in answer:
                    answer.append(new_item)

        return answer

 

브루트 포스 풀이 (이 역시 Time Limit Exceeded)

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        results = []
        nums.sort()

        # 브루트 포스 n^3번 반복
        for i in range(len(nums) - 2):
            # 중복된 값 건너뛰기
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            for j in range(i + 1, len(nums) - 1):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                for k in range(j + 1, len(nums)):
                    if k > j + 1 and nums[k] == nums[k - 1]:
                        continue
                    if nums[i] + nums[j] + nums[k] == 0:
                        results.append([nums[i], nums[j], nums[k]])
                    
        return results

 

 

시간 복잡도를 O(N^2)으로 줄인 풀이

def threeSum(nums):
    result = []
    nums.sort()

    for i in range(len(nums) - 2):
        # 중복값제거
        if i > 0 and nums[i] == nums[i - 1]:
            continue
            
        left, right = i + 1, len(nums) - 1
        while left < right:
            sum = nums[i] + nums[left] + nums[right]
            if sum < 0:
                left += 1
            elif sum > 0:
                right -= 1
            else:
                result.append([nums[i], nums[left], nums[right]])
                while left < right and nums[left] == nums[left + 1]:
                    left += 1
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1
                left += 1
                right -= 1
                #찾게 되면 포인터 이동

    return result

 

 

4. 배열 파티션

https://leetcode.com/problems/array-partition-i/

두개 씩 pair로 묶은 후 각 pair의 최소값을 합했을 때 가장 큰 값을 찾는 문제입니다. 

우선 제일 처음 부터 2개씩 pair로 만드는 경우가 최소값들을 합쳤을 때 가장 큰 값이 되는데

아래처럼 item을 nums라는 배열을 2개씩 잘라 array라는 배열에 넣어준 후 배열을 돌며 최소값을 찾아 result에 합쳐서 return 하였습니다.

def arrayPairSum(self, nums: List[int]) -> int:
    nums.sort()
    array = []
    for i in range(0, len(nums), 2):
        item = nums[i:i + 2]
        array.append(item)
    result = 0
    for i in array:
        result += min(i)
    return result

 

답안지 풀이 1

def arrayPairSum(self, nums: List[int]) -> int:
    sum = 0
    pair = []
    nums.sort()

    for n in nums:
        # 앞에서부터 오름차순으로 페어를 만들어서 합 계산
        pair.append(n)
        if len(pair) == 2:
            sum += min(pair)
            pair = []

    return sum

 

답안지 풀이 2

def arrayPairSum(self, nums: List[int]) -> int:
    sum = 0
    nums.sort()

    for i, n in enumerate(nums):
        # 짝수 번쨰 값의 합 계산
        if i % 2 == 0:
            sum += n

    return sum

 

파이썬 다운 풀이

def arrayPairSum(self, nums: List[int]) -> int:
    return sum(sorted(nums)[::2])
반응형

'부트캠프' 카테고리의 다른 글

[11일차] TIL (DFS)  (0) 2022.03.18
[10일차] TIL - Week1 Test  (0) 2022.03.17
[9일차] TIL (Hash Table)  (0) 2022.03.16
[3일차] TIL  (0) 2022.03.10
[항해99] 3조 미니 프로젝트  (0) 2022.03.07