CP #6 II : Maximum Subarray Divide and Conquer
Daha once O(n) ile cozdugumuz max subarray probleminin, leetcode'da bir de follow up'i var. Problemi divide and conquer ile cozebilir miyiz?
Ilk bakista, verilen dizeyi sol ve sag olarak ikiye ayirip, ayri ayri max sub-array'larini bulmak kolay gozukuyor. Recursive bir fonksiyona bakiyor:
class Solution:
def maxSubarraySum(self, nums, start, end):
# base case: sadece tek eleman varsa, max olarak onu dondur
if start == end:
return nums[start]
else:
# orta noktayi bularak dizeyi ikiye ayirip
# hangisinin max sub array'i buyukse onu donduruyoruz
mid = start + (end-start)//2
return max(self.maxSubarraySum(nums, start, mid),
self.maxSubarraySum(nums, mid+1, end))
def maxSubArray(self, nums):
return self.maxSubarraySum(nums, 0, len(nums)-1)
Bu cozumde tabi ki bir eksik var. Ya max sub array, bizim boldugumuz yerden geciyorsa? Zaten [-2,1,-3,4,-1,2,1,-5,4] icin calistirdigimizda 4 sonucunu alacagiz cunku suanda sadece tek tek elemanlara bakiyoruz.
[-1, 2, 1, -5]
[-1, 2] vs [1, -5]
([-1] vs [2] ) vs ([1] vs [-5])
(-1 vs 2) vs (1 vs -5]
(2) vs (1)
return 2
Seklinde dizedeki en buyuk elemani getirecektir. Cunku bolme noktalarini da hesaba katmiyoruz.
Bolunme noktasindan gecen max sub-arrayi nasil bulabiliriz?
Bolunme noktasini biliyoruz. Bu noktadan sola ve saga, start ve end noktalarina kadar giderek maks sum'i bulabiliriz.
def crossingSubarraySum(self, nums, start, mid, end):
# sola git
left_sum = float("-Infinity")
sm = 0
for t in range(mid, start-1, -1):
sm += nums[t]
left_sum = max(left_sum, sm)
# saga git
sm = 0
right_sum = float("-Infinity")
for k in range(mid+1, end+1):
sm += nums[k]
right_sum = max(right_sum, sm)
# nums[crossing] 2 kere saydik
ret = max(left_sum, right_sum, left_sum+right_sum)
return ret
Seklinde, bolme noktasindan sola ve saga gitmek suretiyle bir max sub array daha elde etmis oluyoruz. Bu iki metodu birlestirirsek,
class Solution:
def maxSubarraySum(self, nums, start, end):
# base case: sadece tek eleman varsa, max olarak onu dondur
if start == end:
return nums[start]
else:
# orta noktayi bularak dizeyi ikiye ayiriyoruz
# soldaki max sub array, sagdaki max sub array ve de
# bolunme noktasindan gecen max sub array'den buyuk olani donduruyoruz
mid = start + (end-start)//2
return max(self.maxSubarraySum(nums, start, mid),
self.maxSubarraySum(nums, mid+1, end),
self.crossingSubarray(nums, start, mid, end))
def maxSubArray(self, nums):
return self.maxSubarraySum(nums, 0, len(nums)-1)
Analiz
Onceki cozum O(n) olmasi itibari ile elbette ki daha performansli. Her adimda dizeyi ikiye boldugumuzden dolayi O(nlogn) olmaktadir.
Yorumlar
Yorum Gönder