力扣 每日一题 525. 连续数组
给定一个二进制数组 nums
, 找到含有相同数量的 0
和 1
的最长连续子数组,并返回该子数组的长度。数组中元素只包含0和1.
今天的是个中等题,需要点思路。
1.刚开始只想到暴力,依次计算区间内0和1的数量,计算时,只需要将区间内的数值相加,如果得到的结果是区间长度的一半,则说明此区间内的0和1数量一致,时间复杂度O(n2)。超时了。
1 public int findMaxLength(int[] nums) { 2 int res = 0; 3 for(int i = 0;i<nums.length-1;i++){ 4 int total = nums[i]; 5 for(int j=i+1;j<nums.length;j++){ 6 total+=nums[j]; 7 if(((j-i+1)&1)!=1&&(total==Math.ceil((j-i+1)/2))){ 8 res = Math.max(res,j-i+1); 9 } 10 } 11 } 12 return res; 13 14 }
2.中间想到用前缀和来快速计算区间内的数值,但是时间复杂度依然是O(n2)。
3.看了提示哈希表,想想是不是有方法使用哈希表来降低前缀和的复杂度。想到如果从prefix[i]= prefix[j]+(j-i)/2的话,就说明j与i之间的数满足条件(0的数量与1的数量相等),那我们就可以使用哈希表,来遍历存储前i个前缀和,key是前缀和,value是最早的前缀和为key的index,计算到j时,判断是否存在prefix[i]-(j-i)/2的值,然后计算即可。测试时,对于数组{0,0,1,0,0,0,1,1}失败,因为prefix[0]=0,prefix[1]=0,正确答案应该是从1开始算起,这里确从0开始算起。
4.大杀招,看题解,之前方向是对了,没有找对方法,题解中将0变为-1,这样就避免了前缀和一致的问题,可以保证前缀和的不一致,这样符合条件的区间和应该为0,则判断条件变为了prefix[i]=prefix[j],更简单易懂。
1 public int findMaxLength(int[] nums) { 2 int res = 0; 3 Map<Integer,Integer> map = new HashMap<>(); 4 int count = 0; 5 map.put(0,-1); 6 for(int i = 0;i<nums.length;i++){ 7 if(nums[i]==1){ 8 count++; 9 }else{ 10 count--; 11 } 12 if(map.containsKey(count)){ 13 res = Math.max(res, i-map.get(count)); 14 }else{ 15 map.put(count,i); 16 } 17 } 18 return res; 19 20 }