【LeetCode&python】915. 分割陣列
阿新 • • 發佈:2020-10-12
題目
給定一個數組A,將其劃分為兩個不相交(沒有公共元素)的連續子陣列left和right,使得:
left中的每個元素都小於或等於right中的每個元素。
left 和right都是非空的。
left要儘可能小。
在完成這樣的分組後返回left的長度。可以保證存在這樣的劃分方法。
示例 1:
輸入:[5,0,3,8,6]
輸出:3
解釋:left = [5,0,3],right = [8,6]
示例 2:
輸入:[1,1,1,0,6,12]
輸出:4
解釋:left = [1,1,1,0],right = [6,12]
思路&程式碼
- 第一次很簡單的設想拿左面陣列部分的最大值和右面陣列部分的最小值比較,如果最大值小於或等於最小值,那麼就可以輸出下標+1作為位置。
時間複雜度是包含一次迴圈和一次max或min呼叫,為O(n^2),很自然地超時了
class Solution:
def partitionDisjoint(self, A: List[int]) -> int:
max_A=A[0]
for i in range(len(A)):
if (max_A < A[i]):
max_A = A[i]
if(max_A<=min(A[i+1::])):
return i+1
- 優化一下,仔細想想,會發現其實如果遍歷陣列的時候,分為兩個狀態其實就可以把複雜度變為O(n)了,即遍歷一遍就可以得到結果。
- record左面的數為左陣列,右面的為右陣列,record作為分界線
- 初始化:把最左邊的數作為候選數和最大值數,狀態設為1,隨時記錄左邊已經遍歷的數的最大值max_left。
- 狀態1:在狀態1的情況下,當向後遍歷時,A[i]都小於候選數,那麼就繼續向後遍歷,保持狀態1,flag=0,同時record下標向後移到i+1,記錄可以切分的點
- 狀態2:在狀態1的情況下,當向後遍歷時,A[i]大於了候選數,此時問題不大,因為如果後面的數依然都大於候選數,那麼是可以保持record不變而直接輸出的,此時只需要將狀態由1跳轉到2,flag=1,record保持不變
- 狀態3:在狀態2的情況下,當向後遍歷時,A[i]又小於了候選數,此時會出現右面的數比左面record之前的陣列部分要小的情況,所以要更新record為i+1,將i+1之前的所有數重新併入左面陣列,返回狀態1,將候選數更新為左面最大數max_left
- 遍歷一遍完成後,輸出record就可以了,時間複雜度為O(n),順利通過
class Solution:
def partitionDisjoint(self, A: List[int]) -> int:
candidate=A[0] # 候選數
max_left=A[0] # 左面已經遍歷過的最大值
record=0 # 記錄下左面全部小於候選數的最後的位置
flag=0 # 標誌位,用於檢測是否遇到大於候選數之後又遇到小於候選數的情況
for i in range(len(A)):
if(flag==0):
if(candidate>A[i]):
record=i
if (candidate < A[i]):
flag=1
if(max_left<=A[i]):
max_left=A[i]
else:
# 遇到大於候選數之後又遇到小於候選數的情況
if (max_left <= A[i]):
max_left = A[i]
if (candidate <= A[i]):
pass
else:
candidate=max_left
flag=0
record=i
return record+1