问题描述:
给定一个数组 A
,将其划分为两个不相交(没有公共元素)的连续子数组left
和 right
, 使得:
left
中的每个元素都小于或等于right
中的每个元素。left
和right
都是非空的。left
要尽可能小。
在完成这样的分组后返回 left 的长度。可以保证存在这样的划分方法。
示例 1:
输入:[5,0,3,8,6]
输出:3
解释:left = [5,0,3],right = [8,6]
提示:
2 <= A.length <= 30000
0 <= A[i] <= 10^6
- 可以保证至少有一种方法能够按题目所描述的那样对
A
进行划分。
问题分析:
先看一个比较容易想的方法,先正向扫描一遍数组,找到左区间的最小值
,然后在从后向前扫描数组,找到右区间的最小值
,最后综合得到的左区间的最大
和右区间的最小
得出答案。时间复杂度O(n),空间复杂度O(n)。
现在介绍另外一种方法,只需扫描一遍数组即可,从大神提交的代码中学来,时间复杂度O(n),空间复杂度O(1)。具体方法如下:
(1)开辟两个变量leftMax
, rightMax
分别表示分割线左边区间的最大值,以及当前数组的最大值。然后,从左向右扫描数组。
(2)如果扫描的当前值小于leftMax
,很显然此时的分割线需要更新,因为右区间所有值都应该大于左区间的所有值。在更新分割线res
时,同时也要更新leftMax
,获取左区间的最大值。并且重置 rightMax
。
(3)如果扫描的当前值大于或等于 leftMax
,就接着判断与 rightMax
的大小关系,如果大于 rightMax
,就更新 rightMax
。直接到结束,就可以得出结果。
Python3实现:
class Solution:
def partitionDisjoint(self, A):
if not A: return 0
leftMax, rightMax = A[0], A[0]
res, n = 1, len(A)
for i in range(n-1):
if A[i] < leftMax:
res = i + 1 # 更新分割线
if rightMax > leftMax:
leftMax = rightMax
rightMax = A[0] # 重置 右端最大值
elif A[i] > rightMax:
rightMax = A[i]
return res
if __name__ == '__main__':
solu = Solution()
A = [5, 0, 3, 8, 6]
print(solu.partitionDisjoint(A))
声明: 总结学习,有问题可以批评指正,大神可以略过哦。
题目链接:915. 分割数组