第一章 引论
递归原则
1.总是要有一种基准情形(基准情形比结束条件的叫法更确切)
2.总是要朝着基准情形的方向推进
3.假设所有的递归调用都能正常运行
4.在求解一个问题的同一个实例时,不要在不同的递归调用中做重复的工作
举例:
def fib(n):
if n<=1:
return 1
else:
return fib(n-1) + fib(n-2)
这个递归fib(n-1)这个方法本身会调用fib(n-2),这样会使运行时间以指数的速度增长
一个解决办法是将已经算出的值存储起来备用
第二章 算法分析
最大子序列和
方法一:穷举法
def max_sub_sequence_sum(ori_list):
length = len(ori_list)
max_sum = 0
for i in range(length):
for j in range(i, length):
this_sum = 0
for k in range(i, j):
this_sum += ori_list[k]
if this_sum > max_sum:
max_sum = this_sum
return max_sum
这种方法复杂度是 O(n**3)
方法二:穷举法
def max_sub_sequence_sum(ori_list):
length = len(ori_list)
max_sum = 0
for i in range(length):
this_sum = 0
for j in range(i, length):
this_sum += ori_list[j]
if this_sum > max_sum:
max_sum = this_sum
第一种方法中k经历的元素j同样会经历,所以这一层循环是不必要的,此时复杂度是O(n**2)
方法三:递归
这个方法使用了“分治”的策略,“分”是把问题分成大致相等的两个子问题,然后对子问题再分,递归的求解。“治”是把子问题的结果合并。
这个问题中,最大子序列和可能在三个地方出现:左部分,右部分,中间部分(更确切的描述为:至少包含左部分最后一个元素和右部分第一个元素的部分,这部分的最大和通过计算左部分的最大和与右部分的最大和相加得到,注意:此处说的左部分和右部分指的是从分割点开始向两侧延伸时取得的最大值)
def max_sub_sum(ori_list, left, right):
if left == right: # left是固定传了0,当==时,就证明list里只有一个元素了,所以这里可以这么写
if ori_list[left] > 0
return ori_list[left]
else:
return 0 # 对这里存有疑问,个人认为,当left == right时,直接return ori_list[left]就可以了,因为对于它的上一层递归来讲,0和负数都不会成为比较中的大值
center = (left + right) / 2
max_left_sum = max_sub_sum(ori_list, left, center)
max_right_sum = max_sub_sum(ori_list, center + 1, right)
max_left_border_sum, left_border_sum = 0, 0
for i in range(center, left - 1, -1):
left_border_sum += ori_list[i]
if left_border_sum > max_left_border_sum:
max_left_border_sum = left_border_sum
max_right_border_sum, right_border_sum = 0, 0
for i in range(center + 1, right + 1, 1):
right_border_sum += ori_list[i]
if right_border_sum > max_right_border_sum:
max_right_border_sum = right_border_sum
return max(max_left_sum, max_right_sum, max_left_border_sum + max_right_border_sum)
max_sub_sum(ori_list, 0, len(ori_list) - 1)
方法四:
def max_sub_sequence_sum(ori_list);
length = len(ori_list)
this_sum = max_sum = 0
for i in range(length):
this_sum += ori_list[i]
if this_sum > max_sum:
max_sum = this_sum
elif this_sum < 0:
this_sum = 0 # 当加出来的数是负数的时候,它一定会使后面和它相加的数变小
return max_sum
先从左开始算,如果没有出现负数,会一直取到从左开始的最大值,如果出现负数的话,证明不能继续向右累加了(此时max_sum还是保留着的)
对分查找
给定一个整数X和一个排序好的list,求X在list中的位置,如果不存在,返回-1
def binary_search(ori_list, x):
left, right = 0, len(ori_list) -1
while left <= right:
mid = (left + right) / 2
if ori_list[mid] < x:
left = mid + 1
elif ori_list[mid] > x:
right = mid - 1
else:
return mid
return -1
幂运算–x的n次幂
def pow(x, n):
if n == 0:
return 1
elif n == 1:
return x # 基准条件
elif n % 2: # 奇数
return pow(x, n/2) * x
else:
return pow(x, n/2)
使用递归,让n次乘法运算变为2logn次
快速排序–这是“分治”策略的另一个例子–友情赠送
def fast_sort(ori_list):
if ori_list:
if len(ori_list) != 1:
fast_value = ori_list[0]
else:
return ori_list
else:
return ori_list
left, right = [], []
for i in ori_list[1:]:
if i < fast_value:
left.append(i)
else:
right.append(i)
return fast_sort(left) + [fast_value] + fast_sort(right)