数组的题目很多很重要,一般和其他知识点综合应用。包括Two pointer,Binary Search,Dynamic Programming,Greedy,Backtracking 等,各类算法都将分别选做一些题目学习交流总结。
这一系列选择出一些非应用上述知识点,而是一些奇思妙想的、套路很深的数组的题目,总结后扩展思路,领悟一些可能会再次遇见的套路,也许可以处理类似的问题。
Given an unsorted integer array, find the smallest missing positive integer.
Example 1:
Input: [1,2,0]
Output: 3
Example 2:
Input: [3,4,-1,1]
Output: 2
Note:
Your algorithm should run in O(n) time and uses constant extra space.
解析:
比较难的一道题,hard,鄙人只先想到了空间复杂度O(n)的算法(当然就是用数组把数字排好了),那么不占用另一个数组怎么办?其实就是在nums上原地交换,交换的限制条件和终止条件是算法的难点。相比之下268题 Missing Number就简单多了。
class Solution:
def firstMissingPositive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
for i in range(len(nums)):
# swap nums[i] to i - 1 then use nums[i - 1] as new target to swap
while nums[i] > 0 and nums[i] <= len(nums) and nums[nums[i] - 1] != nums[i]:
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
for i in range(len(nums)):
if nums[i] != i + 1:
return i + 1
return len(nums) + 1
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋
times.
Note: The algorithm should run in linear time and in O(1) space.
解析:
同样,这道题用O(n)space又是很easy的,后面给出的许多解答也都是这样的,一行代码解决问题,还速度超快:
from collections import Counter
return [k for k,v in Counter(nums).items() if v > len(nums)//3]
用O(1)的算法,是一个很有趣很值得细细品味的算法,总结起来就是“活到最后”,要求频率大于 n/3,因此结果最多有两个,设置两个候选数字,遍历数组,是的话count加1,都不是,都减1,等于0了就下台(换个数)。细细品味,最终剩下的一定是最多的两个,但是count不一定能记录真正的频率,因此第二遍遍历计数。代码如下:
class Solution:
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
n = len(nums)
num1, num2 = 0, 1
cn1, cn2 = 0, 0
res = []
for num in nums:
if num == num1:
cn1 += 1
elif num == num2:
cn2 += 1
elif not cn1:
num1 = num
cn1 += 1
elif not cn2:
num2 = num
cn2 += 1
else:
cn1 -= 1
cn2 -= 1
cn1, cn2 = 0, 0
for num in nums:
if num == num1:
cn1 += 1
elif num == num2:
cn2 += 1
if cn1 > n//3:
res.append(num1)
if cn2 > n//3:
res.append(num2)
return res
当然,有了这道题,169题找出过半的数字,就如出一辙了。
Given an array nums
of n integers where n > 1, return an array output
such that output[i]
is equal to the product of all the elements of nums
except nums[i]
.
Note: Please solve it without division and in O(n).
Follow up:
Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)
解析:
关键是不用除法,O(n)时间,分析每个结果的组成,由它之前的数的乘积和它之后的数的乘积组成,因此作出如下算法,建立output数组,遍历第一遍,依次乘每个元素,output每个位置存放它前面的数字的乘积,再从后向前遍历,output每个位置乘上它后面的数字的乘积,注意对应关系即可。代码如下,很简洁:
class Solution:
def productExceptSelf(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
output = [1]
prod = 1
for num in nums[:-1]:
prod *= num
output.append(prod)
prod = 1
for i in range(len(nums), 0, -1):
output[i-1] *= prod
prod *= nums[i-1]
return output
相当于总结了五道题,没有什么通用的思路,多找规律,下面一节继续选几道题学习总结~