From caaddb56c1bb47732b04a0d4a248846a078ba0c2 Mon Sep 17 00:00:00 2001 From: Levi <5457109+linkpingit@user.noreply.gitee.com> Date: Sun, 13 Jun 2021 17:09:25 +0000 Subject: [PATCH] =?UTF-8?q?22=E5=91=A823=E5=91=A8=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../double_linked_lists_test.py" | 129 +++++++++ .../singly_linked_lists_test.py" | 133 +++++++++ .../stack_test.py" | 54 ++++ ...23\346\236\204\345\237\272\347\241\200.md" | 253 ++++++++++++++++++ .../double_point_test.py" | 111 ++++++++ .../dynamic_test.py" | 74 +++++ .../sort_test.py" | 95 +++++++ 7 files changed, 849 insertions(+) create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/double_linked_lists_test.py" create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/singly_linked_lists_test.py" create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/stack_test.py" create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/\346\225\260\346\215\256\347\273\223\346\236\204\345\237\272\347\241\200.md" create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/double_point_test.py" create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/dynamic_test.py" create mode 100644 "\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/sort_test.py" diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/double_linked_lists_test.py" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/double_linked_lists_test.py" new file mode 100644 index 00000000..4c9ba588 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/double_linked_lists_test.py" @@ -0,0 +1,129 @@ +class Node: + def __init__(self, data): + self.data = data + self.prev = None + self.next = None + + def __str__(self): + return f" {self.data}>" + +class DoubleLinkedList: + def __init__(self): + self.head = None + self.end = None + + def append(self, node): + """ + 1、无节点 head/end->node + 2、尾部添加 node.prev->end, end->node, 尾部end.next-> node + :param node: + :return: + """ + if not self.head: + self.head = node + else: + node.prev = self.end + self.end.next = node + self.end = node + + def insert(self, index, node): + """ + 1、插入是中间节点:node.next->index-1.next node.prev->index-1, index-1.next->node index+1.prev->node + 2、index值超过长度抛出异常 + 3、在头部插入:node.next -> head, head.prev->node, head->node + 4、在尾部插入:同插入加上end->node + :param index: + :param node: + :return: + """ + cur = self.head + if index == 0: + node.next = self.head + self.head.prev = node + self.head = node + return + for i in range(index-1): + cur = cur.next + if cur is None: + raise IndexError("LinkedList insert node exceed max length") + + node.next, node.prev, cur.next = cur.next, cur, node + next = node.next + if not next: + self.end = node + else: + next.prev = node + + def remove(self, node): + """ + 1、移除的是中间节点:cur-1.next->cur.next, cur.next->None, cur+1.prev->cur.prev, cur.prev->None + 2、移除的是end:cur-1.next ->cur.next(None), (cur.next->None), cur.prev->None, end->cur-1 + 3、移除的是head:head -> cur.next, cur.next->None head.prev->None + :param node: + :return: + """ + cur = self.head + while cur: + if cur.data == node.data: + if cur.prev is None: + self.head = cur.next + self.head.prev = None + else: + cur.prev.next = cur.next + if cur.prev and cur.prev.next is None: + self.end = cur.prev + else: + cur.next.prev = cur.prev + + cur.next = None + cur.prev = None + + cur = cur.next + + def reverse(self): + """ + 1、cur.next -> prev, cur.prev -> next + 2、更改head和end + :return: + """ + if self.head and self.head.next: + + cur = self.head.next + prev = self.head + + self.head.next = None + self.end = prev + + while cur: + next = cur.next + cur.next = prev + cur.prev = next + + + prev = cur + cur = next + self.head = prev + else: + return + + def __str__(self): + cur = self.head + result = "" + while cur: + result += str(cur) + "\t" + cur = cur.next + return result + +if __name__ == '__main__': + node1 = Node(1) + node2 = Node(2) + node3 = Node(3) + node4 = Node(4) + doubule_linked = DoubleLinkedList() + doubule_linked.append(node1) + doubule_linked.append(node2) + doubule_linked.append(node3) + doubule_linked.insert(3, node4) + # doubule_linked.remove(node4) + doubule_linked.reverse() + print(doubule_linked) diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/singly_linked_lists_test.py" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/singly_linked_lists_test.py" new file mode 100644 index 00000000..000d5901 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/singly_linked_lists_test.py" @@ -0,0 +1,133 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + + def __str__(self): + return f"" + +class LinkedList: + def __init__(self): + self.head = None + self.end = None + + def append(self, node): + """ + 向链表尾部添加一个节点 + 1、尾部添加:end->node + 2、当前没有节点:head->node + 3、尾部node.next指向新添加的node + :param node: + :return: + """ + if not self.head: + self.head = node + else: + self.end.next = node + self.end = node + + def insert(self, index, node): + """ + 插入 + 1、插入是中间节点:找到index值的节点, node.next->index-1.next index-1.next->node + 2、index值超过当前链表长度,抛出异常 + 3、在头部插入:node.next -> head, head -> node + 4、尾部插入节点:end -> node + :param index: + :param node: + :return: + """ + cur = self.head + if index == 0: + node.next = self.head + self.head = node + return + + for i in range(index-1): + cur = cur.next + if cur is None: + raise IndexError("LinkedList insert node exceed max length") + + node.next, cur.next = cur.next, node + + if node.next is None: + self.end = node + + def remove(self, node): + """ + 删除 + 1、移除的是中间节点:cur-1.next -> cur.next, cur.next -> None + 2、移除的是end:cur-1.next -> cur.next(None), (cur.next -> None), end->cur-1 + 3、移除的是head:head -> cur.next, cur.next -> None + :param node: + :return: + """ + cur = self.head + prev = None + while cur: + if cur.data == node.data: + if prev is None: + self.head = cur.next + else: + prev.next = cur.next + cur.next = None + if prev and prev.next is None: + self.end = prev + return + + prev = cur + cur = cur.next + + + def reverse(self): + """ + 旋转当前链表 + 1、 cur.next -> prev + 2、 更改head和end + :return: + """ + + if self.head and self.head.next: + cur = self.head.next + prev = self.head + + self.head.next = None + self.end = prev + + while cur: + next = cur.next + cur.next = prev + + prev = cur + cur = next + self.head = prev + else: + return + + + + + def __str__(self): + cur = self.head + result = "" + while cur: + result += str(cur) + "\t" + cur = cur.next + return result + + +if __name__ == "__main__": + node1 = Node(1) + node2 = Node(2) + node3 = Node(3) + node4 = Node(4) + linkedlist = LinkedList() + linkedlist.append(node1) + print(f"id(linkedlist.head) == id(node1)?" + str(id(linkedlist.head) == id(node1))) + linkedlist.append(node2) + linkedlist.append(node3) + linkedlist.append(node4) + linkedlist.insert(4, Node(1.5)) + linkedlist.remove(node1) + linkedlist.reverse() + print(linkedlist) diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/stack_test.py" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/stack_test.py" new file mode 100644 index 00000000..bd3a11c3 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/stack_test.py" @@ -0,0 +1,54 @@ +class MyStack: + """ + 栈有固定长度,需要考虑栈溢出和空栈的情况 + top属性 + """ + def __init__(self, _size=10): + self.stark = [] + self.top = -1 + self.size = _size + + def is_full(self): + return self.top == self.size-1 + + def is_empty(self): + return self.top == -1 + + def push(self, item): + """ + :param item: + :return: + """ + if self.is_full(): + raise Exception("StackOverFlow") + self.stark.append(item) + self.top += 1 + + def pop(self): + """ + 判断是否空栈 + :return: + """ + if self.is_empty(): + raise Exception("StackUnderFlow") + self.top -= 1 + return self.stark.pop() + +if __name__ == '__main__': + # 1+2*3 + my_stack = MyStack() + my_stack.push(1) + my_stack.push("+") + my_stack.push(2) + my_stack.push("*") + my_stack.push(3) + while my_stack.top > 0: + item_1 = my_stack.pop() + operator = my_stack.pop() + item_2 = my_stack.pop() + if operator == "*": + my_stack.push(item_1 * item_2) + elif operator == "+": + my_stack.push(item_1 + item_2) + print(my_stack.pop()) + diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/\346\225\260\346\215\256\347\273\223\346\236\204\345\237\272\347\241\200.md" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/\346\225\260\346\215\256\347\273\223\346\236\204\345\237\272\347\241\200.md" new file mode 100644 index 00000000..44f9a42a --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/22\345\221\250\357\274\210\346\225\260\346\215\256\347\273\223\346\236\204\357\274\211/\346\225\260\346\215\256\347\273\223\346\236\204\345\237\272\347\241\200.md" @@ -0,0 +1,253 @@ +# 数据结构基础 + +## 链表和数组 + +> 有序的元素序列 + +链表和数组有什么区别: + +- 实现有序的方式是不一样的,数组是连续的内存,链表是通过持有下一节点内存地址来达到有序的目的 +- 基于上述特性,数组在增删改查时需要消耗大量系统资源来移动元素,而链表只需要修改内存地址 + +### - 数组 + +> Python的list是由数组来实现的 + +有序的元素序列,在内存中为一块连续的内存区域 + +### - 链表 + +通过指针将无序的列表链接起来,每个节点都存储当前节点值和下一节点内存地址 + +- 链表的缺点 + + 链表的查找是从头节点逐个遍历,查找效率低 + +- 链表的应用 + + - 系统的文件系统 + + 磁盘上的文件是通过链表对文件进行目录归类 + + - git的提交节点 + + - 其他数据结构的基础,如树 + +#### · 链表的种类 + +- 单链表 + + ![wwFny.png](https://i.im5i.com/2021/04/06/wwFny.png) + +- 双链表 + + ![ww1B3.png](https://i.im5i.com/2021/04/06/ww1B3.png) + +- 环形链表 + + ![whkhQ.png](https://i.im5i.com/2021/04/06/whkhQ.png) + +#### · 单链表的实现 + +- 声明Node类(自定义) + +## 栈 + +LIFO 先入后出,后入先出 + +![wGeMl.png](https://i.im5i.com/2021/04/11/wGeMl.png) + + + +## 队列 + +FIFO先入先出,后入后出 + +![wGLnn.png](https://i.im5i.com/2021/04/11/wGLnn.png) + +## 散列表 + +> Python中dict本质是散列表 + +散列表也叫`hashmap`,通过`key`映射数组中的一个位置来访问,这个映射函数就叫做散列函数,存放记录的数组也叫散列表 + +![wqqUG.png](https://i.im5i.com/2021/04/10/wqqUG.png) + +- 散列函数有哪些? + + 一个好得散列函数要满足以下条件: 1. 均匀铺满散列表, 节约内存空间; 2. 散列冲突概率低 + + - 直接定址法 + + 适合`key`是连续得或者当前表较小的情况, 否则会有巨大的空间浪费. + + ``` + f(n) = a*n + b + + f(1) = a + b + f(10000) = 10000a + b + ``` + + - 数字分析法 + + 找出`key`值的规律, 构建冲突比较低的散列函数 + + > 比如姓名, 显然姓很容易冲突, 所以根据名来定散列函数. + + - 平方取中法 + + 取关键字平方后的中间做为散列地址 + + - 折叠法 + + 将关键字分割成位数相同的几个部分, 然后取这几个部分的叠加和做为散列函数 + + - 随机数法 + + 选择一个随机函数, 取关键字的随机值做为散列地址, 通过用于关键字长度不同的场合 + + - 除留余数法 + + 取关键字被某个大于散列表长度的数`P`除后得到余数做为散列地址. + +- Python用的是哪种散列函数呢? + + 具体要看数据类型, 使用的散列函数大多也是混合方法. + +- 什么是散列冲突? + + 不同的`key`理应得到不同的散列地址, 散列冲突就是不同`key`得到了同一个散列地址. + +- 如果解决散列冲突? + + - 开放寻址法(Python) + + 线性地扫描散列表, 直到找到一个空单元. + + - 链表法(Java) + + 所有散列值相同的元素都放到相同位置的链表中 + + ![wqCvW.png](https://i.im5i.com/2021/04/10/wqCvW.png) + + - `hashmap`是线程安全的吗? + + - 在`jdk1.8`中, 内部使用的是数组+链表+红黑树, 当进行散列冲突的时候, 注定会有一个数据丢失. + + - 在`python`中, 由于`GIL`内置的数据结构都是线程安全的. 但是对于实际应用中, 线程安全都是**针对的操作.** + + ``` + // 当前的函数是线程安全的 + def foo(a): + my_dict.update({"a": a}) + + + // 通过dis库查看的字节码, 如果关键代码只有一条操作指令, 那就是线程安全的 + import dis + print(dis.dis(foo)) + + // 当前的函数不是线程安全的 + def foo(a): + my_dict['a'] += 1 + ``` + + - 例 + + ``` + from threading import Thread + + my_dict = {"a": 0} + + + def foo(a): + for i in range(10**6): + my_dict['a'] += a + + + if __name__ == "__main__": + thread_1 = Thread(target=foo, args=(1, )) + thread_2 = Thread(target=foo, args=(-1, )) + thread_1.start() + thread_2.start() + + thread_1.join() + thread_2.join() + + print(my_dict) + ``` + + - 什么是线程安全? + + 实际应用的角度来说, 加锁的就是线程安全, 不加锁的就是线程不安全. + + - 为什么在有`GIL`的情况, 线程仍然是不安全的? + + 全局解释器锁只保证了同一个时刻一个线程在运行, 但是不能保证切换到下一个线程还原的现场还有效. + + - `dict`扩容过程以及安全问题? + + `PyDict_SetItem`会计算`key`的散列值, 然后把需要的信息传递给`insertdict`. 在插入之前根据`ma_table`剩余空间的大小来判断是否扩容, 一般超过2/3就会进行扩容. + + > 2/3开始扩容原因就是要给散列函数足够的空间. + +## 树和堆 + +树是一种特殊的链表结构,每个节点下有若干个子节点 + +![wG0V7.png](https://i.im5i.com/2021/04/11/wG0V7.png) + +- 树的分类 + + ![CZN2O.png](https://i.im5i.com/2021/05/30/CZN2O.png) + +- 二叉树 + + - 平衡二叉树 + + 防止二叉树退化成单链表 + + > 左右子树的**高度**相差不超过 1 的树为平衡二叉树 [平衡二叉树详细](https://zhuanlan.zhihu.com/p/56066942#:~:text=%E5%AE%83%E5%85%B7%E6%9C%89%E5%A6%82%E4%B8%8B%E5%87%A0%E4%B8%AA,%E7%BB%9D%E5%AF%B9%E5%80%BC%E4%B8%8D%E8%B6%85%E8%BF%871%E3%80%82) + + > 二叉树的高度有两种定义: + > + > 1、从根节点到最深节点的最长路径的节点数。 + > + > 2、从根到最深节点的最长路径的边数。 + + ![wGa0P.png](https://i.im5i.com/2021/04/11/wGa0P.png) + + - **红黑树** [30张图带你彻底理解红黑树](https://www.jianshu.com/p/e136ec79235c) + + 平衡二叉树要严格保证左右子树高度差不超过1,在实际场景中,平衡二叉树需要频繁调整 + +- 二叉堆 + + 二叉堆是一个完全二叉树,且满足当前任意节点要`<=`或`>=`左右子节点,一般使用数组来实现 + + - 最大堆 + + ![wGMxS.png](https://i.im5i.com/2021/04/11/wGMxS.png) + + - 最小堆同理 + +- B树 + + - B树解决了什么问题? + + B树的目的是在搜索树的基础上优化了磁盘的获取效率 + + > 大部分数据查询瓶颈在磁盘IO上,从磁盘中读取1kb的数据和1b数据消耗的时间基本上是一样的,在平衡二叉树基础上,每个节点尽可能多的存储数据 + + ![wGpND.png](https://i.im5i.com/2021/04/11/wGpND.png) + + + +- B+树 + + - B+树解决了什么问题? + + B+树解决了什么问题? 为了优化B树的查找速度, B树的每一个节点都是数据, 而B+树非子节点存储的是数据的地址(索引值), 子节点存储的是数据, 而且子节点会指向相邻的子节点, 都成一个有序链表. + + > B树适合作文件系统. B+树适合作遍历和查找. + + ![wGkhL.png](https://i.im5i.com/2021/04/11/wGkhL.png) \ No newline at end of file diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/double_point_test.py" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/double_point_test.py" new file mode 100644 index 00000000..99f92568 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/double_point_test.py" @@ -0,0 +1,111 @@ +def removeDuplicates(nums): + """ + 删除有序数组中的重复项 + https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + :param nums: + :return: + """ + n = len(nums) + fast = slow = 1 + while fast < n: + if nums[fast] != nums[fast - 1]: + nums[slow] = nums[fast] + slow += 1 + fast += 1 + return nums[0:slow], slow + +def hasCycle(head): + """ + 环形链表 + https://leetcode-cn.com/problems/linked-list-cycle/ + :param head: + :return: + """ + slow = fast = head + while fast: + fast = fast.next.next + slow = slow.next + if slow == fast: + return True + return False + +def detectCycle(head): + """ + 环形链表II + https://leetcode-cn.com/problems/linked-list-cycle-ii/ + :param head: + :return: + """ + slow = fast = head + while fast: + fast = fast.next.next + slow = slow.next + if slow == fast: + break + + if not fast: + return None + + slow = head + while slow != fast: + slow = slow.next + fast = fast.next + return slow + +def isPalindrome(s): + """ + 验证回文串 + https://leetcode-cn.com/problems/valid-palindrome/ + :param s: + :return: + """ + left = 0 + right = len(s) - 1 + while right >= left: + while not s[left].isalpha(): + left += 1 + + while not s[right].isalpha(): + right -= 1 + + if s[left].lower() == s[right].lower(): + left += 1 + right -= 1 + else: + print("break", left, right) + break + + return left - 1 == right + 1 or left - 1 == right + +def merge(left, right): + result = [] + while left and right: + if left[0] <= right[0]: + result.append(left.pop(0)) + else: + result.append(right.pop(0)) + while left: + result.append(left.pop(0)) + while right: + result.append(right.pop(0)) + return result + +def binary_search(nums, target): + left = 0 + right = len(nums) - 1 + while left <= right: + mid = (left + right) // 2 + if nums[mid] == target: + return mid + elif nums[mid] < target: + left = mid + 1 + elif nums[mid] > target: + right = mid - 1 + return -1 + + +if __name__ == '__main__': + print(removeDuplicates([1,1,2,2,3,3,4,4,5,5,6,6,7,7])) + + print(isPalindrome("A man, a plan, a canal: Panama")) + print(binary_search([-1,0,3,5,9,12], 9)) \ No newline at end of file diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/dynamic_test.py" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/dynamic_test.py" new file mode 100644 index 00000000..1c90d129 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/dynamic_test.py" @@ -0,0 +1,74 @@ +def upstairs(n): + """ + 爬楼梯 + https://leetcode-cn.com/problems/climbing-stairs + dp_table[n] = dp_table[n-1] + dp_table[n-2] + :param n: + :return: + """ + dp_table = [0] * n + + # 初始化dp_table + dp_table[0], dp_table[1] = 1, 2 + + # 填满dp_table, 遍历n即可 + for i in range(2, n): + dp_table[i] = dp_table[i-1] + dp_table[i-2] + + + return dp_table[-1] + +def max_profit(prices): + """ + 买卖股票的最佳时机I + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ + :param prices: + :return: + """ + dp_table = [[0, 0] for _ in range(len(prices))] + + dp_table[0] = [0, 7] + for i in range(1, len(prices)): + # 最大利润 = max(prev最大利润, cur股价 - prv持有股价) + dp_table[i][0] = max(dp_table[i-1][0], prices[i] - dp_table[i-1][1]) + # 持有股票 = min(prev持有股价, cur股价) + dp_table[i][1] = min(dp_table[i-1][1], prices[i]) + return dp_table + +def max_profit2(prices): + """ + 买卖股票的最佳实际II + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + :param prices: + :return: + """ + dp_table = [[0, 0] for _ in range(len(prices))] + + dp_table[0] = [0, -prices[0]] + + for i in range(1, len(prices)): + # 不持有的情况: 1. 上一次没有持有, 不存在卖的操作; 2. 上一次持有, 这次卖了 + dp_table[i][0] = max(dp_table[i-1][0], dp_table[i-1][1] + prices[i]) + # 持有的情况: 1. 上一次持有, 不存在买的操作; 2. 上一次不持有, 这次买了 + dp_table[i][1] = max(dp_table[i-1][1], dp_table[i-1][0] - prices[i]) + return dp_table[-1][0] + + +def coinChange(coins, amount): + """ + 0 <= amount <= 10^4 + 1 <= coins.length <= 12 + dp_table(n) = min(dp_table[n], dp_table[n - coin] + 1) 之前填满容量n最少需要的硬币数和(n-coin)所需硬币数+1中的小值 + :param coins: + :param amount: + :return: + """ + dp_table = [0] + [10001] * amount + print(dp_table) + for coin in coins: + for j in range(coin, amount + 1): + dp_table[j] = min(dp_table[j], dp_table[j - coin] + 1) + print(dp_table) + return dp_table[-1] if dp_table[-1] != 10001 else -1 + + diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/sort_test.py" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/sort_test.py" new file mode 100644 index 00000000..ad880434 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/23\345\221\250\357\274\210\347\256\227\346\263\225\357\274\211/sort_test.py" @@ -0,0 +1,95 @@ + + +def selection_sort(array): + # O(n^2) + for i in range(len(array)-1): + min_index = i + for j in range(i+1, len(array)): + if array[j] < array[min_index]: + min_index = j + # 找到最小值 + if i != min_index: + array[i], array[min_index] = array[min_index], array[i] + +def bubble_sort(array): + # o(n^2) + for i in range(len(array)): + for j in range(len(array)-1-i): + # array[j]表示cur + if array[j] > array[j+1]: + array[j], array[j+1] = array[j+1], array[j] + + +def merge(left, right): + """ + :param left: 左数组 + :param right: 右数组 + :return: + """ + # 因为我们是python的list, 所以不用考虑声明长度 + result = [] + while left and right: + # 比较两个数组的头元素 + if left[0] <= right[0]: + # 通过list.pop删除并返回指定位置的元素 + result.append(left.pop(0)) + else: + result.append(right.pop(0)) + + while left: + result.append(left.pop(0)) + + while right: + result.append(right.pop(0)) + + return result + + +def merge_sort(array): + """ + O(nlogn) + :param array: + :return: + """ + if len(array) < 2: + return array + + middle = len(array) // 2 + left_array = array[:middle] + right_array = array[middle:] + return merge(merge_sort(left_array), merge_sort(right_array)) + +def partition(array, left, right): + """ + :param array: + :param left: 左端索引 + :param right: 右端索引 + :return: + """ + # 为了方便我们理解, 这里选left + pivot = left + + i = j = pivot + 1 + while j <= right: + if array[pivot] > array[j]: + array[i], array[j] = array[j], array[i] + i += 1 + j += 1 + + array[i-1], array[pivot] = array[pivot], array[i-1] + # 返回原pivot值的新索引 + return i-1 + +def quick_sort(array, left, right): + if left < right: + pivot = partition(array, left, right) + quick_sort(array, left, pivot-1) + quick_sort(array, pivot+1, right) + +if __name__ == '__main__': + import random + array = [random.randint(0, 100) for i in range(20)] + quick_sort(array, 0, len(array)-1) + print(array) + + -- Gitee