LeetCode:数组(三)
本组囊括数组相关题目,难度不等:
66.Plus One
题目描述:简单
这道题的思路就是数组末位加一:由于数字是十进制,于是这里考虑的就是逢十进一的情况:(1)末位为9,如149
(2)除了首位外其他多位为9,如199
(1)全为9,如999
解法一:
这里可以看到都是从末位开始判断,于是可以想到逆序遍历数组,如果为9则变为0,直到遇到第一个不为9的数字则加一并返回;再考虑特殊情况,遍历完数组如果都是9,则都变为0后数组最前位置插入一个1即可:
1 class Solution: 2 def plusOne(self, digits: List[int]) -> List[int]: 3 ans = len(digits) -1 4 # 数组中每个元素只存储单个数字很重要! 5 # 主要考虑进位的情况,如99,999,149等 6 # 解法(一):逆序遍历原数组,从数组尾部遍历 7 # 如果遇到数字不是9就+1,并返回 8 # 如果是9,则将当前数字置0,并进入下一轮循环 9 # 循环结束后 10 # 考虑特殊情况:999之类的全为9的数字 11 # 此时需要检查for循环后是否首位数也为0 12 # 即digits[0]是否为0,如果是0,则遇到了特殊情况 13 # 此时需要在数组最前面插入一个1,然后返回即可 14 15 for i in range(ans, -1, -1): 16 if digits[i] != 9: 17 digits[i] += 1 18 return digits 19 else: 20 digits[i] = 0 21 22 if digits[0] == 0: 23 digits.insert(0, 1) 24 return digits
解法二:
Python的赖皮解法,利用str和List的转换:
这里用Python可以取巧,无论这个数组是什么,都可以把它转换为str再加1,再把这个str转化为数组即可,因为题目中说到数组中每个元素只存储单个数字。
1 class Solution: 2 def plusOne(self, digits: List[int]) -> List[int]: 3 ans = len(digits) -1 4 # 数组中每个元素只存储单个数字很重要! 5 # 主要考虑进位的情况,如99,999,199等 6 # 解法一: Python的赖皮解法,利用str和List的转换 7 # sum = 0 8 # for i in range(len(digits)): 9 # sum = sum * 10 + digits[i] 10 11 # return[int(x) for x in str(sum+1)] 12 13 # 这种太赖皮了不提倡
88.Merge Sorted Array
题目描述:简单
题目涉及归并排序
看到题目直觉是直接合并两个数组再进行快速排序,但是这样时间复杂度太高,并且没有利用两个数组本身有序这个信息。
看到有序,考虑双指针,这道题的解法一是从前往后的双指针遍历方法:
解法一
由于这道题需要合并到nums1中,则必须要先保存下nums1原来的元素,然后将新元素输出到nums1数组中。
具体做法是让p、q两个指针分别指向两个数组的开头,然后每次都比较大小,较小的一方则加入到新数组中且指针+1,遍历完后还需判断是否还有需要加入数组的数字。
时间复杂度 : O(n + m),空间复杂度 : O(m)。因为使用了一个新数组保存原来的nums1。
1 class Solution: 2 def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: 3 """ 4 Do not return anything, modify nums1 in-place instead. 5 """ 6 # 直觉是直接合并两个数组再进行快速排序,但是这样时间复杂度太高,并且没有利用两个数组本身有序这个信息。 7 # 看到有序,考虑双指针,这道题的解法一是从前往后的双指针遍历方法:由于这道题需要合并到nums1中,则必须要先保存下nums1原来的元素,然后将新元素输出到nums1数组中。 8 # 具体做法是让p、q两个指针分别指向两个数组的开头,然后每次都比较大小,较小的一方则加入到新数组中且指针+1,遍历完后还需判断是否还有需要加入数组的数字。 9 #时间复杂度 : O(n + m),空间复杂度 : O(m)。因为使用了一个新数组保存原来的nums1 10 nums1_cp = nums1[:m] 11 nums1[:] = [] 12 p = 0 13 q = 0 14 while p < m and q < n: 15 if nums1_cp[p] < nums2[q]: 16 nums1.append(nums1_cp[p]) 17 p += 1 18 else: 19 nums1.append(nums2[q]) 20 q += 1 21 # 遍历完如果还有需要增加的数字,即p和q还没有达到本身数组长的地方 22 if p < m: 23 nums1[p+q:] = nums1_cp[p:] # 本身有序,直接把后面的加入新数组 24 if q < n: 25 nums1[p+q:] = nums2[q:]
这里还有一个问题可以注意一下,在Python3中使用了这样的代码来保存新数组和生成新的nums1:
nums1_copy = nums1[:m],
nums1[:] = []
我们可能会问,为何要使用 nums1[:],是否可以将 nums1[:] 换为 nums1 ?
我们来看一下题目要求:
对于 python3 语言, 题目要求:Do not return anything, modify nums1 in-place instead.即需要就地修改 nums1 对象,而不能新生成一个对象,并让 nums1 指向这一新对象。
注意到 python3 语言, 对象是一个盒子,有具体的地址,而变量名相当于是 "标签",可以贴在盒子上。
我们需要辨析:nums1 = A 和 nums1[:] = A 的不同之处:
nums1 = A # 更改 nums1 这一变量名所指向的对象。让 nums1 变量指向 A 所指向的对象
nums1[:] = A # 对 nums1 指向的对象赋值。把 A 变量指向的对象的值逐个 copy 到 nums1 指向的对象中并覆盖 nums1 指向的对象的原来值。
nums1[:] 等价于 nums1[0:len(nums1)] 相当于取 nums1 对应的对象的一个视图,通常用这个来改变原对象的某几位值。
比如有时候,我们用 A[:2] = [0,1], 来改变 A 所指向的 list 对象的前两个值。
而如果用 A = [0,1], 则是让 A 这一变量名指向新的 list 对象 [0,1],这不符合题目要求。