LeetCode발행일 2025. 4. 1.원본 https://blog.naver.com/jword_/223817560829 ↗

배열 탐색 s. 부분합, 누적합 알고리즘(분할정복)

배열 탐색 s. 부분합, 누적합 알고리즘(분할정복) — #LeetCode #개발자의도구들 #부분합알고리즘 #누적합알고리즘 #누적합 #배열탐색 only 파이썬 목표 참고 ...

#LeetCode#Naver Blog

#LeetCode #개발자의도구들 #부분합알고리즘 #누적합알고리즘 #누적합 #배열탐색

​

​

  • only 파이썬
  • 목표 참고 : 여기

전략 생각하기

LeetCode(medium 53. Maximum Subarray) 51.8%

javascript 코드 예제
                                    📌 아주 유명한 단골 문제이다. 이번 기회에 확실하게 정리하자.

⚠️ n: 1 .. 100000 : 최대 nlogn
🤩 Follow up: divide and conquer

🤔 모든 탐색을 고려하는 것?
>>> O(n²) 🚫time Limit!

🤔 딕셔너리를 사용하여 문제풀기
>>> 자신 보다 왼쪽의 모든 합 중 가장 큰 합을 자기 자신 위치에 기록한다.
    >>> 🤔 자신 기준으로 오른쪽을 고려할 필요없는가?
        >>> 어차피 다음 요소가 자신마저 포함하여 계산하기 때문에 고려하지 않아도된다.
        >>> 항상 본인 위치의 누적합을 계산 해둔다.

1차시도

javascript 코드 예제
                                    ✅ 딕셔너리를 사용한다.
>>> {idx: maxSum}

✅ for i, n in enumerate(nums):
>>> 자신(n)과 i - 1위 딕셔너리 키 값을 조회하여 비교 한다.
    >>> max(자신, 자신 + i - 1)

✅ 딕셔너리의 가장 큰 value가 정답이다.
javascript 코드 예제
                                    class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        mdic = {}

        for i, n in enumerate(nums):
            if i == 0:
                mdic[i] = n
                continue

            mdic[i] = max(n, n + mdic[i - 1])

        result = -9999999999999
        for key in mdic:
            result = max(result, mdic[key])

        return result
  • 정답이다.
  • t: O(n) 5.3% Beats
  • s: O(n) 5.38% Beats

​

  • 좀 더 효율적이게 ?

Follow up을 달성해보자.

분할정복 알고리즘

문제를 풀었다고 바로 넘어가면 하수다. 문제가 나에게 알려주고자하는 것을 모두 빼먹어야한다. 이번 문제는 Follow up으로 divide conquer을 제시햇다.

javascript 코드 예제
                                    📌 divide conquer : 문제를 반으로 나눠서 각 부분을 정복 후, 합쳐서 최종 문제를 푸는 알고리즘

🤔 어떻게 분할 정복을 적용할 수 있을까?
>>> 1. 절반으로 나눈다.
>>> 2. 갂 가장 큰 subarray를 구한다.
    >>> 2.1. 여기서 가장 idx가 낮은 값과, 가장 idx가 높은 값을 저장해둔다.
>>> 3. 가장 낮은 idx에서 가장 높은 idx 범위를 탐색하여 다시 최대값을 초기화 한다.
➡️ 이렇게 생각한 이유는, 연결 중간부가 끊어지면 안된다고 생각했기 때문이다.

Follow up 시도하기

javascript 코드 예제
                                    ✅ dictinary를 주고 받자.
>>> 처음에 전체 값을 업데이트해서 제공

✅ left_dict와 right_dict를 나눈다.
>>> 각각 dict를 업데이트 후 return

✅ dict를 서로 합친다.
>>> left + right
>>> left의 가장 큰 원소가 위치하는 곳 = 시작점
>>> right의 가장 큰 원소가 위치하는 곳 = 끝 점

✅ 분할 된 dict를 서로 합친다.

🤔 divide conquer이 맞을까.. ?
javascript 코드 예제
                                    class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """

        def divquer(ndict):
            print(">>> init <<<\n ndict: {}".format(ndict))
            if len(ndict) <= 1:
                print("return len <= 1: ndict: ", ndict)
                return ndict

            mid = len(ndict) // 2
            print("divide start: mid: {}".format(mid))

            ldict = {}
            for i in range(mid):
                if i not in ndict:
                    print("somethinis wrong... key fault i: {}, ndict: {}".format(i, ndict))
                    continue
                ldict[i] = ndict[i]

            print("left dict maded: ldict: ", ldict)
            rdict = {}
            for i in range(mid, len(ndict)):
                if i not in ndict:
                    print("somethinis wrong... key fault i: {}, ndict: {}".format(i, rdict))
                    continue

                rdict[i] = ndict[i]
            print("right dict maded: rdict ", rdict)

            left = divquer(ldict)
            right = divquer(rdict)

            print("\n[after divide]\n")

            print("left maded: {}\n right maded: {}".format(left, right))

            # combine two dict
            con = {}
            for k in left:
                con[k] = left[k]

            for k in right:
                con[k] = right[k]

            print("con maded: con: ", con)

            for k in con:
                if k - 1 not in con:
                    continue
                con[k] = max(con[k], con[k] + con[k - 1])
            print("<return!> con updated: con: ", con)

            return con

        init = {}
        for i in range(len(nums)):
            init[i] = nums[i]

        result_dict = divquer(init)
        max_sum = max(result_dict.values())

        return max_sum
  • ❌❌❌ 오답이다.
  • dictionary의 ldic, rdic에서 key error가 발생한다.
  • mid값을 단순히 len(ndcit) // 2로 했기 때문
  • 이 로직이 맞는지 근본적으로 의문이 발생함.

​

python Cheats

javascript 코드 예제
                                    🤔 딕셔너리를 n..m까지 분할?
>>> keys = sorted(d)
mid = len(keys) // 2

# 중간 인덱스를 기준으로 분리
left_keys = keys[:mid]
right_keys = keys[mid:]

# 분리된 키를 이용해 딕셔너리 분리 (원하는 경우)
left_dict = {k: d[k] for k in left_keys}
right_dict = {k: d[k] for k in right_keys}

print("Left keys:", left_keys)
print("Right keys:", right_keys)
print("Left dict:", left_dict)
print("Right dict:", right_dict)

🤔 list의 min과 max값 쌈뽕하게 구하기
>>> max(list), min(list)
>>> dict.keys() : key들의 집합, dict.values() : value들의 집합
>>> dict의 경우 바로 min(dict), max(dict)로 해도된다 !

​