即使自己做了几遍,还是没有真正的开窍,领会精髓。第一眼看上去,这是一道数组分割的题目。
给定一个数组
A
,将其划分为两个不相交(没有公共元素)的连续子数组left
和right
, 使得:
left
中的每个元素都小于或等于right
中的每个元素。left
和right
都是非空的。left
要尽可能小
思路一:那么是按索引位置先分割,然后用暴力法比较?很容易得到O(n^3)解决方案(AC)
leetcode对时间复杂度的要求就是如此苛刻。
显然这个是糟糕的实践。class Solution { public int partitionDisjoint(int[] A) { for(int i=1; i < A.length; i++){ int flag = 0; for(int j=0; j < i; j++){ for(int k=i;k<A.length;k++){ if (A[j] > A[k]) flag=1; break; } if(flag == 1) break; } if (flag==0) return i; } return 0; } }
思路二:提炼维度。这里说的维度,是在数组迭代过程中产生的,也是贪心算法的概念。比如你在沙滩上散步,背后留下的是你之前走过的脚印,每个脚印都是独一无二的,轮廓是一样的,但是脚印的力度、深浅、相对位置等因素不尽相同。 当然,如果有必要你可以拿一把尺子、一支笔、一张纸,当你每踩下一步,都能以数据的形式把每一步给量化。
维度只有在集合中才能体现出来。单一的个体不存在大和小,高和低这种概念。在数组中,通过线性迭代会产生集合的维度,这种维度在迭代的过程中也是一直变化的。
回到Leetcode题目本身,
left
中的每个元素都小于或等于right
中的每个元素。显然,left和right各是一个集合,而这里需要考虑left中最大值(leftMax)和right中最小值(rightMin)这2个维度,只有当满足leftMax <= rightMin的时候就能得到答案。class Solution { public int partitionDisjoint(int[] A) { int leftMax = A[0], rightMin = A[0], index=0; for(int i=0;i<A.length;i++){ if(A[i] < rightMin){ rightMin=leftMax; index=i; } leftMax=Math.max(leftMax, A[i]); } return index+1; } }