Bootstrap

代码随想录算法训练营| 数组&链表总结

已经坚持四天了,今天没有布置题目,可以总结一下这四天刷过的数组和链表。1. 

1. 数组

1.1 理论基础

数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标对应的数据。

需要两点注意的是

  1. 数组下标都是从0开始的。
  2. 数组内存空间的地址是连续的

正是因为数组在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。

数组的元素是不能删的,只能覆盖。

二维数组在内存的空间地址不一定连续,不同编程语言的内存管理不一样:

  1. 在C/C++/python(NumPy库)/Go/Rust中二维数组在地址空间上是连续;
  2. Java中的二维数组是数组的数组,行与行之间可能在内存中分散存储,地址不完全连续。

 

 Java中

 所以Java的二维数组在内存中不是 3*4 的连续地址空间,而是四条连续的地址空间组成!

1.2 经典题目

二分法
 middle = left + (right - left) // 2

注意左闭右闭/左闭右开 

  • 暴力解法时间复杂度:O(n)
  • 二分法时间复杂度:O(logn)

 

双指针法(快慢指针法)

通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。 

  • 暴力解法时间复杂度:O(n^2)
  • 双指针时间复杂度:O(n)

慢指针是为了查找和目标值不等的索引,快指针是为了到数组末尾。

 

滑动窗口

不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。

  • 暴力解法时间复杂度:O(n^2)
  • 滑动窗口时间复杂度:O(n)
 模拟行为

 不涉及到什么算法,就是单纯的模拟,注意循环不变量原则

前缀和

前缀和的思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数。

链表

2.1 理论基础

链表的分类:

单链表:每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。链表的入口节点称为链表的头结点也就是head。
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
循环链表:环状,链表首尾相连。
链表的存储方式:

数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。

链表是通过指针域的指针链接在内存中各个节点。

所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

定义链表

class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next

 数组和链表对比

 2.2 经典题型

虚拟头节点

 

链表的基本操作

链表增删改查

反转链表

双指针法/递归法 

while cur:
    temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next
    cur.next = pre #反转
    #更新pre、cur指针
    pre = cur
    cur = temp
删除倒数第N个节点

快慢两个指针,fast先走n+1步,这样同时移动的时候slow指向删除节点的上一个节点(方便做删除操作) 

链表相交

求长度,然后调节指针在同一起点上(末尾位置对齐)

环形链表

1. 集合法,记录已经走过的

2. 快慢指针法,首先要想清楚:

  • 快指针走两步,慢指针走一步,如果有环,快慢指针一定会在环内相遇
  • 如果有环,环的入口位置是多少
    • 链表从起点到环的入口距离为 x。
    • 环的长度为 r。
    • 快慢指针相遇时,慢指针已经移动了 x + y 步,其中 y 是从环入口到相遇点的距离。
    • 可得x=k⋅r−y,其中k是整数,从相遇点再走r−y步回到环的起点,而链表起点到环的入口正好也是x步。

;