A random LeetCode question: No.1567 The length of the longest sub-array whose product is a positive number. It belongs to the array type problem, and the difficulty is medium.
Please click here for the original title:
1567. The longest sub-array length with a positive product
Title description
To give you an array of integers nums, you find product is positive of longest length of the subarray. A sub-array of an array is an array composed of zero or more consecutive numbers in the original array. Please return the length of the longest sub-array whose product is a positive number.
- Example 1: Input: nums = [1,-2,-3,4] Output: 4 Explanation: The product of the array itself is a positive number, and the value is 24.
- Example 2: Input: nums = [0,1,-2,-3,-4] Output: 3 Explanation: The sub-array whose longest product is a positive number is [1,-2,-3] and the product is 6. Note that we cannot also include 0 in the sub-array, because the product is 0, which is not a positive number.
- Example 3: Input: nums = [-1,-2,-3,0,1] Output: 2 Explanation: The longest sub-array whose product is a positive number is [-1,-2] or [-2,-3] .
- Example 4: Input: nums = [-1,2] Output: 1
- Example 5: Input: nums = [1,2,3,5,-6,4,0,10] Output: 4
- In the test, it was found that the performance test case used by LeetCode: an array with a length of 100000, except for nums[3000] which is -1, the rest are all 1.
Problem-solving ideas
Problem focus:
- For an array that does not contain 0, is positive or not 1612c49bf6cab8 depends on the number of negative numbers in it. When the negative number is an even number, the product of the array is positive.
- Product number is positive, regardless of the absolute value of the figures, the array digital symbols are, therefore, can be put into an all positive, all converted to negative -1.
- The requirement in the question is an array of consecutive numbers, so the place where 0 appears must be naturally cut. If there is only one -1 in the divided sub-array, it means that the product of this sub-array is negative (other numbers are all 1 or no other numbers), and it needs to be cut from the position of -1.
- When traversing the sub-array to find the length of the sub-array that meets the criteria, first sort by the length of the array (Python sorting is very convenient), starts from the longest array and finds , which can end the traversal as soon as possible.
The problem-solving process is shown in the figure below:
First write some methods to achieve each small function point
1. The method of format_nums to convert numbers, the input n is a number, and the positive number is converted to 1, and the negative number is converted to -1, and 0 remains unchanged
def format_nums(n):
if n > 0:
return 1
if n < 0:
return -1
return 0
2. Cut the numerator array, first cut by 0, and then cut by the only -1.
The first is the called cut_by_single_negative method, which is responsible for checking whether there is only one -1 in the array. If it is, it will cut the array and the return value will be unified as a list of lists.
# 子数组已经没有0了,检查是否存在唯一一个-1
# 如果有且仅有一个-1,意味着这个子数组乘积肯定为负数,需要再次切分
# 有多个负数的话,就没办法了
def cut_by_single_negative(sub_ls):
ret_ls = []
if sub_ls.count(-1) == 1:
idx = sub_ls.index(-1)
ret_ls.append(sub_ls[:idx])
ret_ls.append(sub_ls[idx+1:])
else:
ret_ls.append(sub_ls)
return ret_ls
You can verify this method:
>>>cut_by_single_negative([1, 1, 1, 1, -1, 1])
[[1, 1, 1, 1], [1]]
Then there is the outer call method cut_by_zero, which divides the array according to 0.
# 对输入的数组按0自然切分为子数组
# 对每个子数组再检查一下是否只有一个-1,有的话也要切分
def cut_by_zero(nums):
# 没有0的数组,检查-1
if 0 not in nums:
return cut_by_single_negative(nums)
# 没有什么技巧,遍历数组,临时存放在tmp中
ret_ls = []
tmp = []
for i in nums:
if i == 0:
# 如果遍历到0,则检查一下tmp中有没有唯一的-1
if len(tmp) != 0:
ret_ls += cut_by_single_negative(tmp)
tmp = []
else:
tmp.append(i)
# 不要忘记尾巴
if len(tmp) != 0:
ret_ls += cut_by_single_negative(tmp)
return ret_ls
Verify this method:
>>>cut_by_zero([1, 1, 1, 1, -1, 1, 0, 1])
[[1, 1, 1, 1], [1], [1]]
used the method of recording subscripts to replace the temporary list variable tmp when implementing the traversal process in this method to reduce additional memory overhead. However, according to the submitted results, the memory savings are limited, and the time overhead has risen more. It is speculated that Python's list implementation mechanism is related, so the method of using temporary variables is reserved here.
3. The is_positive method, to determine whether the product of a sub-array that does not contain 0 is a positive number, just determine whether the number of negative numbers is even.
def is_positive(sub_nums):
negative_count = sub_nums.count(-1)
if negative_count%2 == 0:
return True
else:
return False
Also verify
>>>print(is_positive([1, 1, 1, 1]))
>>>print(is_positive([-1, -1, 1, -1]))
True
False
4. getMaxLenofSub finds the longest sub-array that meets the condition in a sub-array that does not contain 0. The input parameter sub_nums is a sub-array after segmentation. There is no 0 in it, and the number of -1 is not 1. Return as soon as possible by first judging some special circumstances.
def getMaxLenofSub(sub_nums):
len_sub = len(sub_nums)
# 如果这个子数组本身乘积为正,返回数组长度
if is_positive(sub_nums):
return len_sub
# 处理特殊情况,子数组长度只有1的时候,一定只有一个1
if len(sub_nums) == 1:
return 1
# 满足条件的子数组,最长就是子数组的长度
# 从最大长度开始向下递减,只要找到一个满足条件的子数组,即为最长的子数组
for l in range(len_sub-1, 0, -1):
for index in range(len_sub-l+1):
if is_positive(sub_nums[index:index+l]):
return l
return 1
Verify it:
>>>print(getMaxLenofSub([1, 1, 1, 1]))
>>>print(getMaxLenofSub([-1, -1, 1, -1]))
4
3
5. The last is the overall process, first do the number conversion, then divide into sub-arrays, and then sort according to the length of the sub-arrays, so that the traversal process can be ended as soon as possible later. The last step is to traverse all the sub-arrays and find the length of the array that meets the conditions.
def getMaxLen(nums):
# 先把正负整数替换为1和-1
nums = [format_nums(x) for x in nums]
# 按0切分为子数组
ls = cut_by_zero(nums)
# 按子数组的长度排序
ls.sort(key=lambda x:len(x),reverse=True)
# 记录下当前最长的满足条件的子数组长度,初始值为0
max_len_of_all = 0
# 遍历所有子数组
for sub_nums in ls:
# 如果遍历到的子数组的长度小于max_len_of_all
# 意味着不可能得到更长的符合条件的子数组了
# 而数组又是按长度排序的,所以可以断定max_len_of_all即为符合条件最大值
if len(sub_nums) < max_len_of_all:
return max_len_of_all
# 从子数组里找出符合条件的最大长度,并和max_len_of_all比较
sub_max = getMaxLenofSub(sub_nums)
if sub_max > max_len_of_all:
max_len_of_all = sub_max
return max_len_of_all
verify
A few examples mentioned in the title:
>>>nums = [1,-2,-3,4]
>>>getMaxLen(nums)
4
>>>nums = [0,1,-2,-3,-4]
>>>getMaxLen(nums)
3
>>>nums = [-1,-2,-3,0,1]
>>>getMaxLen(nums)
2
>>>nums = [-1,2]
>>>getMaxLen(nums)
1
>>>nums = [1,2,3,5,-6,4,0,10]
>>>getMaxLen(nums)
4
Finally, there is a performance test case, an array with a length of 100,000, to find out the length of the longest sub-array that meets the conditions:
%%time
nums = [1]*100000
nums[3000] = -1
getMaxLen(nums)
CPU times: user 14 ms, sys: 1.27 ms, total: 15.3 ms
Wall time: 15.1 ms
submit
The result submitted to LeetCode is shown in the figure below, and the result of each submission may fluctuate slightly.
My python version
>>> import sys
>>> print(sys.version)
3.7.6 (default, Jan 8 2020, 13:42:34)
[Clang 4.0.1 (tags/RELEASE_401/final)]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。