1 算法合集
import random
# 1 斐波拉契数列
def fib(k):
if k in [0, 1]:
return 1
a, b = 1, 1
for _ in range(3, k + 1):
a, b = b, a + b
return b
print(fib(3))
# 2 二分查找
def two_search(data_list, target):
left = 0
right = len(data_list) - 1
n = 0
while left <= right:
n += 1
mid = int((left + right) / 2)
if data_list[mid] == target:
print("找到了,执行了{}次".format(n))
return
elif data_list[mid] < target:
left = mid + 1
elif data_list[mid] > target:
right = mid - 1
print("没有在列表中找到")
# 3 冒泡排序
def pop_sort(data):
for i in range(len(data)):
for j in range(i + 1, len(data)):
if data[i] > data[j]:
data[i], data[j] = data[j], data[i]
return data
# 4 快速排序
def quick_sort(data):
if data == []:
return []
else:
q_first = data[0]
q_less = quick_sort([i for i in data[1:] if i < q_first])
q_more = quick_sort([i for i in data[1:] if i >= q_first])
return q_less + [q_first] + q_more
# 5 选择排序
def select_sort(data):
for i in range(len(data)):
x = i
for j in range(i, len(data)):
if data[x] > data[j]:
x = j
data[i], data[x] = data[x], data[i]
return data
# 6 希尔(插入)排序
def insert_sort(data):
for i in range(1, len(data)):
x = i
while (x > 0 and data[x] < data[x - 1]):
data[x], data[x - 1] = data[x - 1], data[x]
x -= 1
return data
2-1 什么是递归
- 递归不是算法,但是用途很大
- 递归的定义:在函数内部调用函数本身
- 递归这种技术在很多算法中都有存在:回溯法,动态规划,分治法等
- 递归分为两个过程:递,归,这些都是自动完成的
- 递归一定要终止,怎么写终止条件很重要
2-2 :使用递归实现斐波拉契数列
def fib_test(k):
"""课程中"""
if k in [1, 2]: return 1
return fib_test(k - 2) + fib_test(k - 1)
class Solution:
"""
letcode中
https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/submissions/
"""
def __init__(self):
self.d = {}
def fib(self, k: int) -> int:
if k <= 0: return 0
if k == 1: return 1
if f"f_{k - 2}" not in self.d:
f_2 = self.fib(k - 2)
self.d[f"f_{k - 2}"] = f_2
else:
f_2 = self.d[f"f_{k - 2}"]
if f"f_{k - 1}" not in self.d:
f_1 = self.fib(k - 1)
self.d[f"f_{k - 1}"] = f_1
else:
f_1 = self.d[f"f_{k - 1}"]
# else:
# return self.fib(k-2)+self.fib(k-1)
return (f_2 + f_1) % 1000000007
def fib(self, n: int):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a % 1000000007
if __name__ == '__main__':
d = {}
# s = fib_test(3)
# print(s)
# print(l)
# s = Solution()
# print(s.fib(1000000008))
2-3 非递归方式实现斐波拉契数列
def fib_for(n):
if n <= 0: return 0
n_1, n_2 = 1, 0
for _ in range(n):
n_2, n_1 = n_1, n_1 + n_2
return n_2 % 1000000007
print(fib_for(10))
使用递归往往很耗时,因为重复计算的次数很多
2-4 斐波拉契数列的类似题目
"""
爬樓梯問題分析
一阶 1
二街 2
三阶 3
四阶 5
五阶 8
"""
def pa_lou_ti(n):
f_1 = 1
f_2 = 2
if n == 1: return 1
if n == 2: return 2
for _ in range(3,n):
f_1,f_2 = f_2,f_1+f_2
return f_2
"""
有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少(单位:对)
第一个月 1 (1小 0 中 0 大)
第二个月 1 (0小 1 中 0 大)
第三个月 2 (1小 0 中 1 大)
第四个月 3 (1小 1 中 1 大)
第五个月 5 (2小 1 中 2 大)
第六个月 8 (3小 2 中 3 大)
所以是一个典型的斐波拉契数列问题
"""
def accrue_rabbit(n):
n_1 = 1
n_2 = 1
if n == 1: return 1
if n == 2: return 2
for _ in range(2,n):
n_1,n_2 = n_2,n_1+n_2
return n_2
2-5 循环和递归实现二分查找
二分查找就是限定一个查找值,看这个值是否在有顺序的列表中,将列表分为两部分,将左边的和右边的列表分别和该数值比较,若该数值在某一半中,便在次在新的列表中重复上述过程
# data = [1,7,18,18]
import random
def get_random_list(n=20):
"""获得一个n位的从小打到的随机数列"""
data = [random.randint(1, 100) for i in range(n)]
data = sorted(data, key=lambda x: x, reverse=False)
return data
def bin_search_by_xunhuan(data,s):
"""二分查找,循环法"""
left = 0
right = len(data)-1
n = 0
while left<=right:
n+=1
mid = (left+right)//2
if data[mid] == s:
return '数据已找到,循环了{1}次,索引为{0}'.format(mid,n)
elif s<data[mid]:
right = mid-1
elif s>data[mid]:
left = mid+1
return 'error!!!\n待查找数据不在原列表中'
def bin_search_by_digui(left,right,data,s):
"""二分查找,递归法"""
if left > right:
return '目标数据不在该列表中'
mid = (left+right)//2
if data[mid] == s:
return '数据已找到索引为{0}'.format(mid)
if data[mid] < s:
return bin_search_by_digui(mid+1,right,data,s)
elif data[mid] > s:
return bin_search_by_digui(left,mid-1,data,s)
if __name__ == '__main__':
r = get_random_list()
data = r
# data = [5, 8, 9, 9, 9, 15, 18, 28, 39, 44, 44, 51, 53, 56, 64, 65, 75, 77, 88, 90]
# r = bin_search_by_xunhuan(data,15)
# print(r)
s = random.sample(data,1)[0] # 在列表中随机找一个元素
print(s)
r = bin_search_by_digui(0,len(data)-1,data, s)
print(r)
2-6 :汉诺塔实现
阶乘
def jc(n):
"""阶乘"""
if n ==1:return 1
else:
return n*jc(n-1)
if __name__ == '__main__':
r = jc(2)
print(r)
r = jc(5)
print(r)
r = jc(10)
print(r)
汉诺塔
#1. 大傻: 只搬动一号盘
#2. 1. 叫谁来做,: 1. 从哪个柱子搬动到哪个柱子,中间柱子
#2. 2. 搬动自己负责的柱子 3. 从哪个柱子搬动到哪个柱子,中间柱子
def move(index, start, mid, end):
if index == 1:
print("{}-->{}".format(start,end))
return
else:
move(index-1, start, end, mid)
print("{}-->{}".format(start, end))
move(index-1, mid, start, end)
if __name__ == "__main__":
move(5, "A", "B", "C")
"""
优点:
简单,回溯法
递归都能通过非递归的方式完成
缺点:
1. 递归由于是函数调用自身,而函数调用是有时间和空间的消耗的:
每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址以及临时变量,而往栈中压入数据和弹出数据都需要时间。->效率
2. 递归中很多计算都是重复的,由于其本质是把一个问题分解成两个或者多个小问题,
多个小问题存在相互重叠的部分,则存在重复计算,如fibonacci斐波那契数列的递归实现。->效率
3. 调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。->性能
"""
冒泡排序
冒泡排序:它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成
时间复杂度:O(n²)
空间复杂度:O(1)
稳定性:稳定
def bubble_sort(blist):
count = len(blist)
for i in range(count):
for j in range(i + 1, count):
if blist[i] > blist[j]:
blist[i], blist[j] = blist[j], blist[i]
return blist
blist = bubble_sort([4, 5, 6, 7, 3, 2, 6, 9, 8])
print(blist)
快速排序
快速排序:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
时间复杂度:O(nlog₂n)
空间复杂度:O(nlog₂n)
稳定性:不稳定
def quick_sort(qlist):
if qlist == []:
return []
else:
qfirst = qlist[0]
qless = quick_sort([l for l in qlist[1:] if l < qfirst])
qmore = quick_sort([m for m in qlist[1:] if m >= qfirst])
return qless + [qfirst] + qmore
qlist = quick_sort([4, 5, 6, 7, 3, 2, 6, 9, 8])
print(qlist)
选择排序
选择排序:第1趟,在待排序记录r1 ~ r[n]中选出最小的记录,将它与r1交换;第2趟,在待排序记录r2 ~ r[n]中选出最小的记录,将它与r2交换;以此类推,第i趟在待排序记录r[i] ~ r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕
时间复杂度:O(n²)
空间复杂度:O(1)
稳定性:不稳定
def select_sort(slist):
for i in range(len(slist)):
x = i
for j in range(i, len(slist)):
if slist[j] < slist[x]:
x = j
slist[i], slist[x] = slist[x], slist[i]
return slist
slist = select_sort([4, 5, 6, 7, 3, 2, 6, 9, 8])
print(slist)
Python算法和数据结构
1 Python算法常考题
排序+查找 ,重中之重
1 常考排序算法:冒泡排序,快速排序,归并排序,堆排序
2 线性查找,二分查找
3 能独立实现代码(手写),能够分析时间空间复杂度
2 Python数据结构常考题
python web后端常考数据结构
1 常见的数据结构链表,队列,栈,二叉树,堆
2 使用内置结构实现高级数据结构,比如内置的list.deque实现栈
3 leetcode或者《剑指offer》
常考数据结构值链表
链表有单链表,双链表,循环双端链表
1 如何使用Python来表示链表结构
2 实现链表常见操作,比如插入节点,反转链表,合并多个链表等
3 Leetcode联系常见的题
3 链表反转
class Solution(object):
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
def helper(last, cur):
if cur == None: return cur
next = cur.next
cur.next = last
if next == None: return cur
return helper(cur, next)
return helper(None, head)
4 常考数据结构之队列
1 如何使用Python实现队列
2 实现队列的append和pop操作,如何做到先进先出
3 使用Python的list或者collections.deque实现队列
python实现队列,(队列是先进先出)
from collections import deque
class Queue:
def __init__(self):
self.items = deque()
def append(self, val):
return self.items.append(val)
def pop(self):
return self.items.popleft()
def empty(self):
return len(self.items) == 0
def test_queue():
q = Queue()
q.append(0)
q.append(1)
q.append(2)
q.append(3)
print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())
test_queue()
5 常考数据结构之栈(后进先出)
栈(stack)是后进先出结构
from collections import deque
class Stack(object):
def __init__(self):
self.items = deque()
def push(self, val):
return self.items.append(val)
def pop(self):
return self.items.pop()
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.pop())
print(stack.pop())
print(stack.pop())
6 常考数据结构之字典与集合
1 Python dict/set底层都是哈希表
2 根据哈希函快速定位一个元素,平均查找O(1),非常快
3 不断加入元素会引起哈希表重新开辟空间,拷贝之前元素到新数组
7 哈希表如何解决冲突
链接法和开放寻址法
1 元素key冲突之后使用一个链表填充相同key的元素
2 开放寻址发是冲突之后根据一种方式(二次探查)寻找下一个可用的槽
3 cPython使用的二次探查
8 常考数据结构之二叉树
先序,中序,后序遍历
-
先(根)序:先处理根,之后是左子树,然后是右子树
-
中(根)序:先处理左子树,然后是根,然后是右子树
-
后根序:先处理左子树,然后是右子树,最后是根
9 常考数据结构之堆
使用python的heapq实现堆
import heapq
class Topk:
"""
获取大量元素,topk个大元素,固定内存
思路:
1 先放入元素前k个建立一个最小堆
2 迭代剩余元素
如果当前元素小于堆顶元素,跳过该元素(肯定不是钱k大)
否则替换堆顶元素为当前元素,并重新调整堆
"""
def __init__(self, iterable, k):
self.minheap = []
self.capacity = k
self.iterable = iterable
def push(self, val):
if len(self.minheap) >= self.capacity:
min_val = self.minheap[0]
if val < min_val: # 当然你可以直接if val > min_val操作,这里只是显示指出跳出这个元素
pass
else:
heapq.heapreplace(self.minheap, val) # 返回并且pip堆顶对小值,推入新的val值并调整堆
else:
heapq.heappush(self.minheap, val)
def get_topk(self):
for val in self.iterable:
self.push(val)
return self.minheap
def test():
import random
i = list(range(1000))
print(len(i))
random.shuffle(i)
print(len(i))
# print(i)
_ = Topk(i, 10)
print(_.get_topk())
test()
10 Python白板编程(手写代码)
11 链表
链表涉及到指针操作较为复杂,容易出错,经常用作常考题
- 熟悉链表的定义和常见操作
- 常考题:删除一个链表节点
- 常考题:合并两个有序链表
删除链表中的节点
# https://leetcode-cn.com/problems/delete-node-in-a-linked-list/
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
nextnode = node.next
after_next_node = nextnode.next
node.val = nextnode.val
node.next = after_next_node
合并两个有序链表
# https://leetcode-cn.com/problems/merge-two-sorted-lists/
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1: return l2
if not l2: return l1
if l1.val <= l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l2.next, l1)
return l2
12 Python数据结构常考题之二叉树
- 二叉树的操作很多可以用递归的方式解决
二叉树的镜像
# https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if root:
root.left, root.right = root.right, root.left
self.mirrorTree(root.left)
self.mirrorTree(root.right)
return root
二叉树的层序遍历
# https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:return []
res=[]
cur_nodes = [root]
next_nodes = []
res.append([i.val for i in cur_nodes])
while cur_nodes or next_nodes:
for node in cur_nodes:
if node.left:
next_nodes.append(node.left)
if node.right:
next_nodes.append(node.right)
if next_nodes:
res.append(
[i.val for i in next_nodes]
)
cur_nodes = next_nodes
next_nodes = []
return res
13 栈和队列
后进先出 vs先进先出
- 熟练掌握用Python的list或者 collections.deque()实现栈和队列
- 常考题:用栈实现队列
- leetcode implement-queue-using-stacks
# https://leetcode-cn.com/problems/implement-queue-using-stacks/
from collections import deque
class Stack:
def __init__(self):
self.items = deque()
def push(self, val):
return self.items.append(val)
def pop(self):
return self.items.pop()
def top(self):
return self.items[-1]
def empty(self):
return len(self.items) == 0
class MyQueue:
def __init__(self):
"""
Initialize your data structure here.
"""
self.s1 = Stack()
self.s2 = Stack()
def push(self, x: int) -> None:
"""
Push element x to the back of queue.
"""
self.s1.push(x)
def pop(self) -> int:
"""
Removes the element from in front of queue and returns that element.
"""
if not self.s2.empty():
return self.s2.pop()
while not self.s1.empty():
val = self.s1.pop()
self.s2.push(val)
return self.s2.pop()
def peek(self) -> int:
"""
Get the front element.
"""
if not self.s2.empty():
return self.s2.top()
while not self.s1.empty():
val = self.s1.pop()
self.s2.push(val)
return self.s2.top()
def empty(self) -> bool:
"""
Returns whether the queue is empty.
"""
return self.s1.empty() and self.s2.empty()
14 数据结构之堆
堆常考题基本围绕在合并多个有序(数组、链表):Topk问题
1 理解堆的概念,堆是完全二叉树,有最大堆和最小堆
2 会使用Python内置的heapq模块实现堆的操作
3 常考题:合并k个有序链表leetcode merge-k-sorted-list
合并K个排序链表
# Definition for singly-linked list.
from heapq import heappop, heapify
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def mergeKLists(self, lists: ListNode):
h = []
for node in lists:
while node:
h.append(node.val)
node = node.next
if not lists: return
heapify(h)
root = ListNode(heappop(h))
curnode = root
while h:
curnode.next = ListNode(heappop(h))
curnode = curnode.next
return root
15 Python字符串常考算法题
了解常用的字符串操作
1 Python内置了很多字符串操作,比如split,upper,repalce
2 反转一个字符串
3 如何判断一个数字是否是回文数(双端变化法)
# https://leetcode-cn.com/problems/reverse-string/
# 反转字符串
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
# s.reverse()
beg = 0
last = len(s)-1
while beg<last:
s[beg],s[last] = s[last], s[beg]
beg +=1
last -= 1
回文数
# https://leetcode-cn.com/problems/palindrome-number/
class Solution:
def isPalindrome(self, x: int) -> bool:
if x<0:return False
# x = [i for i in str(x)]
x = str(x)
beg,last = 0, len(x) - 1
while beg < last:
if x[beg] != x[last]:
return False
beg += 1
last -=1
return True
16 算法与数据结构练习题:反转链表
# https://leetcode-cn.com/problems/reverse-linked-list/
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
def helper(last,cur):
if cur == None: return cur
next = cur.next
cur.next = last
if next == None:return cur
return helper(cur,next)
return helper(None, head)