数据结构以及相关算法

Posted by lily on April 7, 2023
  • 主流的数据结构与必须要掌握的算法思想

    数据结构与算法简介

  1. 程序 = “数据结构”+“算法”
    1. 数据结构是程序实现的工具
    2. 算法是动态的存在于程序运行的过程
  2. 数据结构表达了多种数据间的关系

    基本数据结构

  • 逻辑结构:线性结构、树、图
  • 物理结构:数据结构在实际代码中的实现

    刷题顺序参考:

    数组——>链表——>哈希表——>字符串——>栈与队列——>树——>回溯——>贪心——>动态规划——>图论——>高级数据结构


学习思维导图

v2-9b19241550c3617d373c99e55bc56b44_r.jpg

时间复杂度和空间复杂度

时间复杂度

  • 概念:用于评估代码运行所需要时长的衡量单位
    • O(1),一段代码运行一个单位数量级
    • O(n),一层n次的循环
    • O(n^2),两层循环嵌套,一共循环了n^2次
    • O(logn),也可以写作log2n,循环次数不固定,刚开始是n的循环,接下来每次循环都会导致循环次数减半。
      while n>1:      #输入n = 64
        print(n)    #循环本要执行64次
        n = n//2    #结果在循环内部,循环减半,n减半变为32,循环需要执行32次..
      
  • 时间复杂度排序
    • 时间复杂度高的式子运行时间比时间复杂度低的运行得慢
    • O(1)<O(logn)<O(n)<O(nlogn)=O(logn^2)<O(n^2)<O(n^3)

线性结构

列表

  • 列表存储数据:连续存储
    • image.png
  • 列表与数组的2点区别
  • 列表的内存存放与c中数组存放的区别
    • python中列表存放数据的地址
    • c中数组直接存放数据
    • 按下标索引: a[2] —–> id(a[2]) = id(a[0]) + 2*4
      • 32位的机器中整数占4字节
  • 列表的删除、插入、新增是如何实现的,时间复杂度是多少

    数据结构

    栈(Stack)

    image.png

  • 用列表来实现栈
  • 栈只能在一端进行操作,后进先出,只能在列表末端进行插入和删除操作
  • push:添加元素
  • pop:删除栈顶元素
  • get top:查看栈顶元素
  • 括号匹配问题
    class Stack(self):
    

    队列(Queue)

    image.png

  • 队列的实现方法——用py自带模块 ```python from collections import deque

que1 = deque(maxlen=10) que1.append(1) #队首进队(右边) que1.append([2,3]) #可以添加列表 que1.popleft() # 队尾出队(左边) ‘'’双向队列,左边为尾,右边为首’’’ que1.appendleft(4) #队尾进队(左边) que1.pop() #队首出队(右边) ‘'’当加入元素超过列表长度之后,队尾自动出队’’’


- 迷宫问题
   - 深度优先搜索(回溯法)
   - 广度优先搜索(可以找到最短路径,同时出发,第一个结束)
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1238904/1660826012819-de3926ac-a62c-4d3d-8809-6706e54ee1cf.png#clientId=u20fc1457-c296-4&errorMessage=unknown%20error&from=paste&height=247&id=u8fac7cd4&name=image.png&originHeight=347&originWidth=481&originalType=binary&ratio=1&rotation=0&showTitle=false&size=151627&status=error&style=none&taskId=u8e0742c0-e760-4c60-b8a1-660a3bea495&title=&width=342.66668701171875)
# 双指针法
## 移除数组元素
```java
int i = 0;
int menberID = target;
for (int j = 0; j < total; i++, j++) {
    p = team[j];
    while (j<total && p == memberID) {
        j++;
    }
//team数组后面几位是置空的 team[j] == null
//无论置空为否, 都要把后面元素的值复制到前面来 
    team[i] = team[j];
}
//退出条件满足之时(j < total),i的值理应是total,
//但由于又进循环进行了一次判断,所以i多加了1
total = i-1;

滑动窗口:

当需要查找数组内某段_长度不固定且满足某些条件的数时,需要边遍历边控制窗口内的数,找到这些满足条件的长度不固定的数_

  1. example1:

**给定一个二进制数组 nums , 计算其中最大连续 1 的个数。** **输入:**nums = [1,1,0,1,1,1] **输出:**3 **解释:**开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.

res = 0
slow, fast = 0, 0
while fast < len(nums):
    if nums[fast] == 1:
        fast += 1
        continue
        res = max(res, fast - slow)
        # fast跳过0的情况,且时不用计算res值
    while fast<len(nums) and nums[fast] == 0:
        fast += 1
    slow = fast
return max(res, fast - slow)
  • 统一边界条件:当快指针指向0还是下一个值1的时候,慢指针指向哪里
  • 慢指针如何移动
  • 什么时候可以计算长度:当快指针指向0还是下一个值1的时候进行计算长度

KMP算法

见笔记KMP算法总结篇

内置堆模块

Manacher算法

双端队列

单调栈

优先级队列