面试-算法笔记
目录
程序计时器
import time
import random
def cal_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print("%s Running time: %s"%(func.__name__, (end_time - start_time)))
return res
return wrapper
排序算法
堆排序
import random
import time
def sift(li, low, high):
i = low
tmp = li[low]
j = 2 * i + 1
while j <= high:
if j < high and li[j + 1] > li[j]:
j += 1
if li[j] > li[i]:
li[i], li[j] = li[j], li[i]
i = j
j = 2 * i + 1
else:
break
@cal_time
def tree_sort(li, low, high):
n = len(li) - 1
# 构造堆
for i in range((n - 1) // 2, -1, -1):
sift(li, i, n)
# 挨个出数
for j in range(n , -1, -1):
li[0], li[j] = li[j], li[0]
sift(li, 0, j - 1)
if __name__ == "__main__":
li = list(range(10000))
random.shuffle(li)
tree_sort(li, 0, len(li) - 1)
print(li)
快速排序
def partition(li, low, high):
tmp = li[low]
while low < high:
while low < high and li[high] >= tmp: # 莫忘记添加 等号
high -= 1
li[low] = li[high]
while low < high and li[low] <= tmp: # 莫忘记添加 等号
low += 1
li[high] = li[low]
else:
li[low] = tmp # 大致分完类后别忘了在左右指针汇合处添加基准值,也就是最后填坑;
return low
def quick_sort(li, low, high):
if low < high:
mid = partition(li, low, high)
quick_sort(li, low, mid - 1)
quick_sort(li, mid + 1, high)
@cal_time
def majia(*args, **kwargs):
quick_sort(*args, **kwargs)
li = list(range(10000))
random.shuffle(li)
majia(li, 0, len(li) - 1)
print(li)
快速排序 --- 代码 002
import time
import random
def quick_sort(nums):
if len(nums) <= 1:
return nums
# First
m = nums[0]
nums = nums[1:]
# Second
nums_l = [i for i in nums if i < m]
nums_r = [i for i in nums if i >= m]
# Third
return quick_sort(nums_l) + [m, ] + quick_sort(nums_r)
li = list(range(22))
random.shuffle(li)
# li = [2, 5, 6, 10, 5, 6]
res = quick_sort(li)
print(res)
冒泡排序
@cal_time
def bubble_sort(li):
n = len(li) - 1
for i in range(n, -1, -1):
for j in range(i):
if li[j] > li[j + 1]:
li[j], li[j + 1] = li[j + 1], li[j]
# 冒泡 排序优化:
def optimize_bubble_sort(li):
for i in range(len(li)-1):
exchange = False
for j in range(len(li)-i-1):
li[j],li[j+1] = li[j+1],li[j]
exchange = True
if not exchange:
break
# 最好: O(n) 中等 和 最坏 为 O(n^2)
li = list(range(1000))
random.shuffle(li)
bubble_sort(li)
print(li)
选择排序
# 选择排序: 学算法的 时候尽量 不要用 内置函数
# 不稳定 , 飞着 换的
@cal_time
def select_sort(li):
for i in range(len(li)):
min_pos = i
for j in range(i+1,len(li)):
if li[min_pos] > li[j]:
min_pos = j
li[min_pos],li[i] = li[i],li[min_pos]
li = list(range(1000))
random.shuffle(li) # 打乱
select_sort(li)
print(li)
插入排序
@cal_time
def tea_insert_sort(li):
for i in range(1,len(li)):
tmp = li[i]
j = i - 1
while j >= 0 and li[j] > tmp:
li[j+1] = li[j]
j -= 1
li[j+1] = tmp
# 插入排序 优化
@cal_time
def insert_sort02(li): # O(n^2)
for s in range(1,len(li)):
tmp = li[s]
for n in range(s-1,-2,-1):
if li[n] < tmp:
break
li[n+1] = li[n]
li[n+1] = tmp
li= list(range(10000))
random.shuffle(li)
tea_insert_sort(li)
基数排序
# 基数 排序
@cal_time
def radix_sort(li): # O(nk) k 表示位数 , 和 最大数 的 位数 有关系 , 只能 处理整数
max_num = max(li)
i = 0
while (10 ** i < max_num):
buckets = [[] for _ in range(10)]
for val in li:
digit = val // (10 ** i) % 10
buckets[digit].append(val)
li.clear()
for bucket in buckets:
for val in bucket:
li.append(val)
i += 1
li = list(range(1000))
random.shuffle(li)
radix_sort(li)
print(li)
归并排序
def merge(li,low,mid,high):
# mid 为 分割线 左边 元素的 下标
# 列表 两段有序 [low,mid] ,[mid+1,high]
i= low
j = mid + 1
li_tmp = [] # 升序
while i <= mid and j <= high:
if li[i] < li[j]:
li_tmp.append(li[i])
i += 1
else:
li_tmp.append(li[j])
j += 1
while i <= mid:
li_tmp.append(li[i])
i +=1
while j <= high:
li_tmp.append(li[j])
j += 1
# 把 排序后的列表 写入到 原先列表的 [low,high] 的区间中 去
# for i in range(low,high+1):
# li[i] = li_tmp[i-low]
li[low:high+1] = li_tmp
def merge_sort(li,low,high):
if low < high:
mid = (low + high) // 2
merge_sort(li,low,mid)
merge_sort(li,mid+1,high)
merge(li,low,mid,high)
# 套个 马甲
@cal_time
def majia(li,low,high):
merge_sort(li,low,high)
li = list(range(100))
random.shuffle(li)
majia(li,0,len(li)-1)
print(li)
计数排序
@cal_time
def count_sort(li,max_num=100):
count = [0 for _ in range(max_num+1)]
for val in li:
count[val] += 1
li.clear()
for i,v in enumerate(count):
for s in range(v):
li.append(i)
li = [random.randint(0,100) for _ in range(10000)]
random.shuffle(li)
count_sort(li)
print(li)
希尔排序
def insert_sort(li,d): # O(n^2)
for s in range(d,len(li)):
tmp = li[s]
for n in range(s-d,-2,-d):
if li[n] < tmp:
break
li[n+d] = li[n]
li[n+d] = tmp
# 希尔排序
@cal_time
def shell_sort(li):
d = len(li) // 2
while d > 0:
insert_sort(li,d)
d = d // 2
li= list(range(100))
shell_sort(li)
print(li)
迷宫问题
suosuo = [
[1,1,1,1,1,1,1,1,1,1],
[1,0,0,1,0,0,0,1,0,1],
[1,0,0,1,0,0,0,1,0,1],
[1,0,0,0,0,1,1,0,0,1],
[1,0,1,1,1,0,0,0,0,1],
[1,0,0,0,1,0,0,0,0,1],
[1,0,1,0,0,0,1,0,0,1],
[1,0,1,1,1,0,1,1,0,1],
[1,1,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1]
]
dirs = [
lambda x, y: (x - 1, y),
lambda x, y: (x, y + 1),
lambda x, y: (x + 1, y),
lambda x, y: (x, y - 1),
]
# 深度优先
def migong_deep(x1, y1, x2, y2):
stack = []
stack.append((x1, y1))
suosuo[x1][y1] = 2
while len(stack) > 0:
cur_node = stack[-1]
if cur_node == (x2, y2):
print("到达终点,")
for i,v in enumerate(stack):
print(i, v)
return True
for d in dirs:
next_node = d(*cur_node)
if suosuo[next_node[0]][next_node[1]] == 0:
stack.append(next_node)
suosuo[next_node[0]][next_node[1]] = 2
break
else:
stack.pop()
else:
print("There is no way")
return False
# 广度优先
from collections import deque
def migong_wide(x1, y1, x2, y2):
q= deque()
q.append((x1, y1, -1))
suosuo[x1][y1] = 2
traceback = []
while len(q) > 0:
cur_node = q.popleft()
traceback.append(cur_node)
if cur_node[:-1] == (x2, y2):
path = []
i = len(traceback) - 1
while i >= 0:
path.append(traceback[i][:-1])
i = traceback[i][2]
path.reverse()
for i,v in enumerate(path):
print(i, v)
return True
for d in dirs:
next_x, next_y = d(cur_node[0], cur_node[1])
if suosuo[next_x][next_y] == 0:
q.append((next_x, next_y, len(traceback) - 1))
suosuo[next_x][next_y] = 2
else:
print("There is no way")
return False
migong_wide(1, 1, 8, 8)
# migong_deep(1, 1, 8, 8)
斐波那契数列
def feibo(n): #
if n == 0 or n == 1:
return 1
return feibonaqi(n-1) + feibonaqi(n-2)
# 避免重复计算
@cal_time
def feibo01(n): # S(n) = O(n) = T(n)
li = [1,1]
for s in range(2, n+1):
li.append(li[-1] + li[-2])
return li[n]
# 节省空间
@cal
def feibo02(n):
a = 1
b = 1
for s in range(2,n+1):
c =- a + b
a = b
b = c
return c
斐波那契 --- 装饰器写法
def cache(func):
cache_res = {}
def die (*args, **kwargs):
if args[0] in cache_res:
return cache_res[args[0]]
res = func(*args, **kwargs)
cache_res[args[0]] = res
return res
return die
@cache
def fibonaqid(num):
if num < 2:
return num
return fibonaqid(num - 1) + fibonaqid(num - 2)
if __name__ == "__main__":
num = 10
res = fibonaqid(num)
print(f" 计算 {num} 的斐波那契数值为 {res}")
汉诺塔问题
# 汉诺塔 问题
def hanoi(n,A,B,C):
if n>0:
hanoi(n-1,A,C,B)
print('%s--->%s'%(A,C))
hanoi(n-1,B,A,C)
hanoi(4,'A','B','C')
二分查找
# 二分法查找 (候选区 )
def bin_search(collect,value): # O(logn)
low = 0
high = len(collect)-1
while high >= low:
mid = (low + high) // 2
if collect[mid] == value:
return mid
if value > collect[mid]:
low = mid + 1
else:
high = mid -1
return -1
li = list(range(1,4500545,3))
print(bin_search(li,22))
# 递归 式的 二分查找
# 但: 尾递归 ,会变为循环,一样的 效率 ,对 python 而言 没有优化 ,还是慢
def bin_recursive(li,val,low,high):
if low <= high:
mid = (low + high) // 2
if val == li[mid]:
return mid
elif val < li[mid]:
return bin_recursive(li,val,low,mid-1)
else:
return bin_recursive(li,val,mid+1,high)
else:
return -1
li = list(range(1,4500545,3))
print(bin_recursive(li,22,0,1000))
单链表
class Node:
def __init__(self,data=None):
self.data = data
self.next = None
# head ---> a ----> b----> c -----> d
head = Node() # data 可以 来存储 链表的长度
a = Node(1)
b = Node(2)
c = Node(3)
d = Node(4)
head.next = a # 头结点 , 空链表 表示为 haad 节点 的 next 无 指向
a.next = b
b.next = c
c.next = d
# while 遍历 链表
# while 1:
# node = a.next
# if not node:
# break
# print(node.data)
# a = node
# 迭代 遍历 输出 链表 每个元素
def output(start_node):
if not start_node:
return
print(start_node.data)
output(start_node.next)
class LinkList:
def __init__(self,li,method='head'):
self.head = None
method ='create_linklist_'+ method.strip()
if hasattr(self,method):
func = getattr(self,method)
func(li)
else:
raise ValueError('method argument is Error......')
def create_linklist_head(self,li): # 头插法 将 一个 列表 转化 为链表
self.head = Node(0)
for v in li:
n = Node(v)
n.next = self.head.next
self.head.next = n
self.head.data += 1
def create_linklist_tail(self,li): # 尾 插法, 将一个列表转化 为链表
self.head = Node(0)
tail = self.head
for i in li:
v = Node(i)
tail.next = v
tail = v
self.head.data += 1
def shiwei(self,start): # 迭代 遍历链表
if not start :
return
print(start.data)
self.shiwei(start.next)
def print_linklist(self):
start = self.head
self.shiwei(start)
# 链表 的 删除
# curNode.next = curNode.next.next
# 文件系统 和 区块链
# 硬盘 的基本单位 为 block = 4 K
from collections import deque
shi = deque()
li = range(20)
shiwei = LinkList(li,method='head')
shiwei.print_linklist()
找错, 快速排序
def _quick_sort_version2(li): # 有误
print("-------------", len(li))
if not li:
return []
if len(li) == 1:
return li
if len(li) == 2:
if li[0] > li[1]:
li.reverse()
return li
# if len(li) == 3:
tmp = li[0]
left = [v for v in li[1:] if v < tmp ]
right = [v for v in li[1:] if v >= tmp]
left = _quick_sort_version2(left)
right = _quick_sort_version2(right)
return left + [tmp,] + right
@cal_time
def quick_sort_version2(li):
_quick_sort_version2(li)
li = list(range(100))
random.shuffle(li)
quick_sort_version2(li)
print(li)