LeetCode 数组题
268. 缺失数字
题目描述: 从一个包含 0到n 的 n-1 个数的序列nums中,找出缺失的那个数。要求线性时间复杂度,仅使用额外常数空间。
思路1: 生成一个长度加1,元素全为-1的数组a,将nums中的元素作为索引给a赋值,最后元素为-1的索引即为nums缺失的元素。但是这种做法应该不满足额外常数空间的要求。
Python代码:
class Solution(object):
def missingNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
a = [-1] * (len(nums)+1)
for i in range(len(nums)):
a[nums[i]] = i
for i in range(len(a)):
if a[i] == -1:
return i
思路2: 借鉴评论里的一种解题思路,巧妙地利用了“ 从0到n”这一条件与数组元素的和的关系。看来“找到”某个元素不一定非要挨个去找。
Python代码:
class Solution(object):
def missingNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
sum1 = n*(n+1) / 2
sum2 = sum(nums)
return sum1-sum2
283. 移动0
题目描述: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
思路1: 把遇到的0元素与最近的非0元素互换位置。
Python代码:
class Solution(object):
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
i, j = 0, 1
while j < len(nums):
if nums[j] != 0 and nums[i] == 0:
nums[i], nums[j] = nums[j], nums[i]
if nums[i] != 0:
i += 1
j += 1
思路2: 觉得思路1比较简单,于是找找有没有惊喜的解题方式,看到一种差不多,但是更简洁的解题方法。就是两个指针i,j,当指针i碰到非0元素就与j交换元素,然后i,j均向前移动一位;如果i遇到的是0元素,则i向前移动一位。
这样的做法保证的是,如果刚开始是非0元素,则i,j会同时移动且指向同一个元素,不会使非0元素的位置替换;如果刚开始就为0元素,则j指向了0元素,而i继续往前找到非0元素与j进行交换。所以在遍历过程中,要么i,j处在同一位置一起向前,要么i在前j在后,中间由0隔开且j指向0元素。因此交换i,j就可以完成非0元素前移,相应的0元素后移。
本来比较简明的方法,好像说得有点麻烦,多画画草稿更好理解。
Python代码:
class Solution(object):
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
j = 0
for i in range(len(nums)):
if nums[i] != 0:
nums[i], nums[j] = nums[j], nums[i]
j += 1
414. 第三大的数
题目描述: 给定一个非空数组,返回此数组中第三大的数值。如果该数组的数值小于三个,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。
思路1: 本来想通过遍历和判断在一个新的数组中insert()当前的数,但是时间复杂度度好像不满足O(n)。所以改为通过遍历和判断为3个变量赋值。
Python代码:
class Solution(object):
def thirdMax(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n1 = n2 = n3 = -float('inf')
for num in nums:
if num > n1:
n3 = n2
n2 = n1
n1 = num
if n2 < num < n1:
n3 = n2
n2 = num
if n3 < num < n2:
n3 = num
if n3 > -float('inf'):
return n3
else:
return n1
思路2: 感觉思路1比较老实,寻找参考思路。
287. 寻找重复数组
题目描述: 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间,其中至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
题目要求: 不能改变数组;只能使用O(1)的空间;时间复杂度小于O(n2)。
思路1: 利用快慢指针,参考博文
理解快慢指针。主要就是,把nums数组看做链表,如果快慢指针相遇则说明链表有环,因为如果没有环,慢指针是追不上快指针的。
根据自己的理解画了如下的图示,帮助理解。
步骤1:先将数组转换成列表
步骤2:移动快慢指针,慢指针一次前进一个结点,快指针一次前进两个结点,直到相遇。
步骤3:看列表的话,快慢指针已经指向相同的位置和相同的元素,但是实际遍历数组时只是遍历到了同一个位置,并没有找到两个相同的元素。所以第二个循环要在环内以相同的速度移动快慢指针,直到找到相同元素(我也理解不了为什么这样就能找到,画草稿理解吧)。
Python代码:
class Solution(object):
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
slow = nums[0]
fast = nums[nums[0]]
while slow != fast:
slow = nums[slow]
fast = nums[nums[fast]]
fast = 0
while nums[slow] != nums[fast]:
slow = nums[slow]
fast = nums[fast]
return nums[slow]
560. 和为k的子数组
题目描述: 给定一个整数数组和一个整数 k,找到该数组中和为 k 的连续的子数组的个数。
思路1: 果真太太太菜,除了暴力解题想不出别的方法了。于是学习到的解题思路:利用前缀和和哈希表。
- 前缀和: 从下标为0的数到当前位置的数的连续和. 比如[1, 2, 3]的前缀和是[1, 3, 6]; [-1, -1]的前缀和是[-1, -2].
- 哈希表: 类似于python的字典
于是求到某一个位置的前缀和之后,可以通过两种方法判断到当前位置的连续子数组中有多少个的和为k了:(1) 当前前缀和是否为k;(2) 当前前缀和减去前面已求出的前缀和的值是否为k(表明中间的子数组和为k)
Python代码:
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
count = 0
hushMap = {}
acc = 0
for num in nums:
acc += num
if acc == k:
count += 1
if (acc-k) in hushMap:
count += hushMap[acc-k]
if acc in hushMap:
hushMap[acc] += 1
else:
hushMap[acc] = 1
return count