written by 五氧化二钒
数组
带着问题来学习:
问题1.数组和列表、集合之间有什么不同?
解决思路:画出表格,做总结。
答:
数据结构 | 顺序 | 长度 | 元素类型 | 重复元素 | Python |
---|---|---|---|---|---|
集合 | 没有顺序 不可以通过下标访问 | 长度可变 .add()增加元素 .remove()删除元素 .clear()清空集合 | 没限制 | 没有重复元素 | set1 = {1,2,3} 只声明{}是字典 |
列表 (线性列表) (链表) | 有顺序 可以通过list1[n]访问 | 长度可变 .append()增加元素 .remove()删除第一个匹配到的元素 .pop(n)弹出索引为n的元素 .pop()弹出最后一个元素 .clear()清空列表 | 没限制 | 可以有重复元素 | list1 = [] |
元组 | 有顺序 可以通过tup1[n]访问 | 长度不可变 元素也不可变,不能增加删除修改 | 没限制 | 可以有重复元素 | tup1 = (1,"帅") |
字典 | 3.10版有顺序 可以通过键访问值 | 长度可变 增加/修改元素dict[key] = value 删除元素del my_dict['age'] 清空元素my_dict.clear() | 字典的值没有限制 字典的键必须是不可变的 | 不能重复,键值对一一对应 | my_dict = {'键1': 1, '键2': 2, '键3': 3} |
问题2.如何理解数组的读取、查找、插入、删除等 基本操作
?
解决思路:描述数组的操作过程。
答:
数组的操作 | 操作步骤 | 时间复杂度 |
---|---|---|
读取元素 | 1.找到当前数组索引为0的位置。 2.将内存地址加上索引值,即为目标位置。 | O(1) |
查找元素 | 1.找到当前数组索引为0的位置。 2.逐个向后检测 | O(N) |
插入元素(尾部) | 1.根据数组首地址和长度,计算出末尾地址,直接插入即可。 | O(1) |
插入元素(中间) | 1.将要插入位置的元素和之后的元素挨个向后移一位。 2.插入到目标位置。 | O(N) |
删除元素 | 1.删除当前元素位置。 2.之后元素逐个上位一位。 | O(N) |
例题1.寻找数组的中心索引
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
原题链接:724. 寻找数组的中心下标 - 力扣(LeetCode)
解题思路:遍历每一个元素,直到左边sum=右边sum为止。
答:
class Solution: def findMiddleIndex(self, nums): #先计算总和吧 total = sum(nums) sumleft = 0 sumright = 0 #遍历吧 for i in range(len(nums)): #看看左边(包括自身) sumleft = sumleft + nums[i] #看看右边(不包括自身) #右边可以用总的减左边的 sumright = total - sumleft if sumleft-nums[i] == sumright: return i return -1 nums = [] solu = Solution() n = solu.findMiddleIndex(nums) print(n)
例题2.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
原题链接:35. 搜索插入位置 - 力扣(LeetCode)
解题思路:遍历寻找即可
答1(实现了插入):
class Solution: def searchInsert(self, nums, target) : #先判断是否在数组中 if(target in nums): #存在,完成 n = nums.index(target) return n else: #不存在 #找自己的位置 #第一种寻找方法:顺序查找 for i in range(len(nums)): if target < nums[i]: nums.append(None) #挨个移后方元素(包括i) for j in range(len(nums)-i-1): nums[-(j+1)] = nums[-(j+2)] nums[i] = target return nums else: continue nums.append(target) return nums solution = Solution() print(solution.searchInsert([1,2,4,5,6],7))
答2(只找到插入位置即可):
class Solution: def searchInsert(self, nums, target) : #数字位于数组中时,输出下标 if(target in nums): return nums.index(target) else: #遍历,如果target小于某一个数了,那么这个数下标就是要插入的位置 for i in range(len(nums)): if target < nums[i]: return i else: continue #遍历完成后,若没有return return len(nums) solu = Solution() print(solu.searchInsert([1,2,3,4],5))
例题3.合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
解决思路:覆盖的区域都染色成1,没覆盖的不染色默认0。最后全部遍历一遍,输出结果。
答1(区间为双闭区间的情况):
#区间为双闭区间的情况 class Solution: def merge(self, intervals): #先列出所有右界,找到最大的,开个新数组 right = [] for i in range(len(intervals)): right.append(intervals[i][1]) #注意下标 newlist = [0]*(max(right)) #涂色 #先把两端涂了再说 #列出所有左界 left = [] for i in range(len(intervals)): left.append(intervals[i][0]) #开始涂两端的色 for i in range(len(newlist)): if(((i+1) in left) or ((i+1) in right)): newlist[i] = 1 else: continue #开始涂中间的色 #寻找两端差值大于1的 for i in intervals: if (i[1] - i[0])>1: for j in range(i[1] - i[0]): #找定位元素i[0]i[1] newlist[i[0]+j] = 1 #输出结果 #若不存在0则输出大团圆 if (0 not in newlist): return [[1,len(newlist)]] #若存在0,列出所有1的下标 else: index = [index for index,value in enumerate(newlist) if value == 1] #遍历所有1的下标 #设置记录点 result_head = [] result_tail = [] for i in index: #如果当前下标-1不在index中,该位置(下标+1)就是一个区间的开端 if (i-1) not in index: result_head.append(i+1) #如果当前下标+1不在index中,该位置(下标+1)就是一个区间的结尾 if (i+1) not in index: result_tail.append(i+1) #输出结果 resultlist = [] for i,j in zip(result_head,result_tail): resultlist.append([i,j]) return resultlist solu = Solution() print(solu.merge([[1,4],[5,6]]))
答2(区间为左闭右开的情况):
#区间为左闭右开的情况 class Solution: def merge(self, intervals): #先列出所有右界,找到最大的,开个新数组 right = [] for i in range(len(intervals)): right.append(intervals[i][1]) #注意下标 newlist = [0]*(max(right)) #涂色 #先把左端涂了再说 #列出所有左界 left = [] for i in range(len(intervals)): left.append(intervals[i][0]) #开始涂左端的色 for i in range(len(newlist)): if((i+1) in left): newlist[i] = 1 else: continue #开始涂中间的色 #寻找两端差值大于等于2的,才需要涂(右端不涂) for i in intervals: if (i[1] - i[0])>=2: for j in range(i[1] - i[0] - 1): #找定位元素i[0]i[1],这里应该是把左端又涂了一遍 newlist[i[0]+j] = 1 print(newlist) #输出结果 #若不存在0则输出大团圆 if (0 not in newlist): return [[1,len(newlist)]] #若存在0,列出所有1的下标 else: index = [index for index,value in enumerate(newlist) if value == 1] #遍历所有1的下标 #设置记录点 result_head = [] result_tail = [] for i in index: #如果当前下标-1不在index中,该位置(下标+1)就是一个区间的开端 if (i-1) not in index: result_head.append(i+1) #如果当前下标+1不在index中,该位置(下标+2)就是一个区间的结尾(开区间) if (i+1) not in index: result_tail.append(i+2) #输出结果 resultlist = [] for i,j in zip(result_head,result_tail): resultlist.append([i,j]) return resultlist solu = Solution() print(solu.merge([[1,4],[0,4]]))
答3(区间为左闭右开的情况+从0开始情况):
class Solution: def merge(self, intervals: List[List[int]]) -> List[List[int]]: #先列出所有右界,找到最大的,开个新数组 right = [] for i in range(len(intervals)): right.append(intervals[i][1]) #注意下标 newlist = ([0]*(max(right)+1)) #涂色 #列出所有左界 left = [] for i in range(len(intervals)): left.append(intervals[i][0]) #开始涂左端+中间的色 #寻找两端差值大于等于2的,才需要涂(右端不涂) for i in intervals: if (i[1] - i[0])>=2: for j in range(i[1] - i[0]): #找定位元素i[0]i[1],这里应该是把左端又涂了一遍 newlist[i[0]+j] = 1 #把右端写为0,这个是为了防止(n,n)的情况发生 for i in intervals: newlist[i[1]] = 0 #输出结果 #若不存在0则输出大团圆(不可能存在0) if (0 not in newlist): return "疑似异常" #若存在0,列出所有1的下标 else: index = [index for index,value in enumerate(newlist) if value == 1] #遍历所有1的下标 #设置记录点 result_head = [] result_tail = [] for i in index: #如果当前下标-1不在index中,该位置(下标)就是一个区间的开端 if (i-1) not in index: result_head.append(i) #如果当前下标+1不在index中,该位置(下标+1)就是一个区间的结尾(开区间) if (i+1) not in index: result_tail.append(i+1) #输出结果 resultlist = [] for i,j in zip(result_head,result_tail): resultlist.append([i,j]) return resultlist
答4(区间为左闭右开的情况+从0开始情况+去除(n,n)bug):
ps:所谓(n,n)bug就是在算左闭右开区间时,(n,n)应该被视为单独区间,不与相邻区间合并
代码先不写了
从上面的五个答案可以看出,没有经过任何算法学习的我,即使能写出相对正确的答案,也会漏掉一些情况或是写出bug,而且代码真的很冗余,行数也多,总之就是全是缺点。接下来展示的是网络上别人的正确答案,可以以此来管中窥豹一下算法的作用。
答5(参考答案):
解题思路:
class Solution: def merge(self, intervals: List[List[int]]) -> List[List[int]]: """ 方法:排序 """ intervals.sort(key = lambda x : x[0]) merges = list() for interval in intervals: if not merges or merges[-1][-1] < interval[0]: merges.append(interval) else: merges[-1][-1] = max(merges[-1][-1], interval[1]) return merges