面试-算法笔记


程序计时器

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)
posted @ 2019-10-24 13:32  梭梭666  阅读(329)  评论(0编辑  收藏  举报
返回顶部