算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间。
- 例如函数执行的基本操作次数:F(N) = 2N2+2N+10,则对应的时间复杂度是:O(N2),N的2次方
1、数组中元素差值比较
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一次计算,设计一个算法来计算你所能获取的最大值。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(价格 = 1)的时候买入,在第 5 天(价格 = 6)的时候抛出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
请给出时间复杂度O(n)方案,并给出测试用例设计。
def maxMoney(args):
max_money = 0
if not isinstance(args, list):
print("必须传递数组类型")
return max_money
if len(args) <= 1:
return max_money
for i in range(len(args)-1):
# 数组截取,从剩余的数组中,选取最大值,然后与起始值做减法
max_element = max(args[i+1:len(args)])
if max_element > args[i]:
max_money_temp = max_element - args[i]
# max_money与每次循环时计算的最大值作比较,取最大值
max_money = max(max_money, max_money_temp)
return max_money
print(maxMoney("aa")) # 必须传递数组类型 0
print(maxMoney([])) # 0
print(maxMoney([7])) # 0
print(maxMoney([0])) # 0
print(maxMoney([-1])) # 0
print(maxMoney([-1, 0])) # 股票价格不能包含负数 0
print(maxMoney([7, 8])) # 1
print(maxMoney([7, 7])) # 0
print(maxMoney([7, 6])) # 0
print(maxMoney([7, 1, 5, 3, 6, 4])) # 5
2. 数组中的两个元素匹配
设计一个算法,找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。
示例 1:
输入: nums = [5,6,5], target = 11,输出: [[5,6]]
示例 2:
输入: nums = [5,6,5,6], target = 11,输出: [[5,6],[5,6]]
# 方法1:排序后双向指针循环,将target与最左边最小值和最右边最大值之和做比较。排序后时间复杂度为O(NlogN)
def matchTarget(args, target):
matches = []
if not isinstance(args, list):
print("必须传递数组类型")
return matches
if len(args) < 2:
return matches
args.sort() # 会改变原数组值
i = 0
j = len(args)-1
while i < j:
if args[i] + args[j] < target:
i += 1
elif args[i] + args[j] > target:
j -= 1
else:
matches.append([args[i], args[j]])
i += 1
j -= 1
return matches
# 方法二:
# hash做存储target-args[i]的值
# 如果tmp中不存在对应target-args[i]的值,则说明当前元素和之前的都不匹配。然后需要将当前元素添加到tmp中。
# 如果tmp中存在对应target-args[i]的值,则说明当前元素和之前的某个元素匹配了。然后tmp中移除匹配的元素(这样就是用tmp达到了一个不重复使用之前的),并且将匹配数数据添加到matches中
# 时间复杂度:O(N)
def matchTarget2(args, target):
matches = []
matches2 = {}
if not isinstance(args, list):
print("必须传递数组类型")
return matches
if len(args) < 2:
return matches
tmp = {}
for i in range(len(args)):
num = args[i]
remain = target - num
# 如果当前元素和tmp中的元素之和不等于target,把当前元素存储到tmp中,用于后续比较
if remain not in tmp:
tmp[num] = i
# 如果当前元素和tmp中的元素之和等于target,把tmp中匹配到的元素移除,并且把当前匹配到数据添加到matches
else:
tmp.pop(remain)
matches.append([remain, num])
# 缺点:循环结束之后tmp不一定为{}空字典
# print(tmp)
return matches
# 方法3: 嵌套循环,时间复杂度:O(N^2),N的2次方。
# 难点:怎么保证不重复使用数据?
def matchTarget3(args, target):
matches = []
if not isinstance(args, list):
print("必须传递数组类型")
return matches
if len(args) < 2:
return matches
length = len(args)
for i in range(length):
j = i+1
print("-------, i:j", i, j)
for j in range(length):
if i != j and args[i] + args[j] == target:
matches.append([args[i], args[j]])
return matches
print(matchTarget2([5,6,5], 11)) # [[5, 6]]
print(matchTarget2([5,6,5,6], 11)) # [[5, 6], [5, 6]]
# print(matchTarget2([4,5,3,6], 9)) # [[4, 5], [3, 6]]
3、求数组中的第二大的元素
- 注意点1:第二大的数需要考虑最大数有重复的情况,不要被套路了。如果最大数有重复的话就不能直接sort()排序之后再取倒数第二个的值了。
- 解决思路:列表元素去重+排序+取值
1、使用set()集合去重
arr = [1, 2, 5, 6, 4, 6]
b = set(arr)
sorted(b)[-2] # 返回第二大的元素,5
2、使用numpy包去重
import numpy
arr = [1, 2, 5, 6, 4, 6]
b = numpy.unique(arr) # array([1, 2, 4, 5, 6]),不会改变原数组
sorted(b)[-2] # 返回第二大的元素,5
4、计算数组元素重复次数
1、使用内置list.count(i)函数
a = [1,1,2,3,3,3]
b = set(a) # (1,2,3)
for i in b:
a.count(i)
2、使用Python字典
Python字典是一种键值对的数据类型,可以用来统计元素出现的次数。具体方法是将每个元素作为字典的键,出现的次数作为字典的值。例如:
a = [1, 2, 3, 4, 3, 2, 1]
d = {}
for i in a:
if i in d:
d[i] += 1
else:
d[i] = 1
print(d) # 输出{1: 2, 2: 2, 3: 2, 4: 1}