leetcode基本数据结构之链表刷题分析

链表

1、解题技巧

1.1、利用快慢指针(有时候需要用到三个指针)

  • 链表的翻转
  • 寻找倒数第k个元素
  • 寻找链表中中间元素
  • 判断链表是否有环

1.2、构建一个虚假的链表头 哑节点方便进行输出尤其牵扯到链表的头部节点需要进行变动时**

  • 两个排序链表,进行排序整合
  • 将链表的奇偶数按原定顺序分离,生成前半部分为奇数,后半部分为偶数

1.3、删除链表节点

记录删除节点的前一个节点

2、如何训练该技巧

在纸上或者白班上画出节点之间的互相关系画出修改的方法

凭空想象是比较困难的

画在白班上,还能让面试官清楚的看到思路

3、习题总结与分类

3.1、找到链表中的某个节点

  • 链表的中间节点:快指针与慢指针,快指针一次走两个节点,慢指针一次走一次节点,当快指针走到链表尾部时,慢指针走到链表的中间节点

  • 链表的倒数第k个节点:快指针先走k步;然后快慢指针一起走,当快指针走到尾部时,慢指针走到倒数第k个节点

  • 链表中下一个更大节点:方法1:暴力法遍历整条链表在其后面找到每个链表大于它的值;方法二:可以使用栈,单调栈,从前遍历节点,对于每个节点,与栈中所对应的值进行比较,若大于栈中顶的值则将栈中元素全部出栈,栈中元素存储索引所对应的值的下一个更大值为当前遍历的节点,

3.2、删除链表中的节点

最好采用哨兵机制,定义一个哑节点dummyNode,令dummyNode.next=head
删除节点需要保存待删除节点的前一个节点cur,因此往往在遍历的时候,需要保存前一个节点

  • 移除链表中某个特定的值:因为可能吧头节点删除,可以定义一个哑巴节点指向头节点;定义一个cur节点遍历整个链表,pre保存遍历节点的前一个节点,方便删除;发现cur.val=val则删除pre.next=cur.next; cur =cur.next,否则pre=pre.next, cur=cur.next

  • 移除链表中的重复节点(链表未排序):可以暴力的双重循环,对链表中的每个节点进行判断;;进行改进:定义cur节点遍历整个链表,定义HashSet保存已经遍历链表中不重复的元素,若发现cur在链表中已经存在则将cur节点从链表删除,否则将cur节点加入到链表中

  • 移除链表中的重复节点(链表已经排序):使用双指针pre,curpre.val=cur.valpre.next=cur.next,cur=cur.next,否则pre=pre.next,cur=cur.next

  • 移除链表中的重复节点(链表已经排序):双指针,和上提的区别就是把所有的重复元素都删除,一个都不保留。

3.3、分析链表的结构

在链表的中间节点,链表的反转,链表的快慢指针,双指针的基础上进行整合,分析

  • 链表是否有环:快慢指针,`块指针一次走两步,慢指针一次走一步,若有环则必然有相遇的时候,若无环则快指针会很快走到链表的尾部
  • 链表环的入口:在上提的基础上进行,关键是:发现规律,找到第一次相遇的节点,之后令一个节点指向头节点,相遇节点与头结点不断向后走,载次相遇则为环的入口(具体看连接中的图)
  • 判断两条链表是否为相交链表:定义两个指针,从两个链表中分别向前走,若走到自己链表的尾部则接着走另外一条链表,若最后两条指针相遇则说明存在交点
  • 回文链表:回文的特点是从前往后和从后往前读的顺序一样。可以使用快慢指针法找到链表的中间节点;将中间节点之后的节点进行反转;则此时遍历中间节点前链表和中间节点之后已反转的链表是否相等则可

3.4、更改链表的结构(链表的合并,链表位置的调整,链表的反转)

  • 注意保存可能用到的节点,因为往往需要修改大量节点,更改节点法
  • 通常定义哑节点方便返回
  • 思考是否可以用递归法
  • 反转链表:定义两个指针reverSeTop(已经反转链表的首部)nonReverseTop未反转链表的首部,不断向后遍历,令ListNode next = nonReverSerTop.next; nonReverseTop.next=reverSeTop; reveseTop=nonReverSeTop;nonReverSeTop=next,在遍历链表的时候进行节点指针的更改实现反转
  • 反转链表中的某些节点m-n:`在上提的基础上,先找到m节点,然后进行反转
  • 合并两个有序链表:方法1:定义两个节点分别指向两个链表的首部,不断比较连个节点当前的值,添加到新链表的后面,当一条链表遍历完成后,则可以将为遍历完的链表直接添加到新链表的后面;方法2:采用递归: 终止条件:两条链表分别名为 l1 和 l2,当 l1 为空或 l2 为空时结束; 本级递归内容:如果 l1 的 val 值更小,则将 l1.next 与排序好的链表头相接,l2 同理 参考
  • 两两交换链表中的节点:方法1保存多个节点,遍历整个链表,调节指针;方法2:递归法
  • 将链表分为奇数与偶数链表:将奇节点放在一个链表里,偶链表放在另一个链表里。然后把偶链表接在奇链表的尾部。
  • 分隔链表:将链表平均分
  • 旋转链表:注意链表的旋转的特点是具有周期性的,因此若链表长度为n,旋转k次则等价于旋转k%n次;旋转可找到链表的倒数第k个节点,将从倒数第k个节点指向链表的头部,倒数第k-1为尾部节点即可;循环旋转,但其实本质上是将尾部向前数第K个元素作为头,原来的头接到原来的尾上
  • 链表中两数相加返回新链表:定义两个指针,遍历两个链表,计算和并确定是否需要进位

3.5、链表的排序

步常用,用到数组排序的思想,归并,选择排序

  • 哑节点的技巧
  • 需要保存其前面的节点
  • 选择排序:遍历链表,对链表中的每个接点,从链表的头部开始确定应该插入的位置,确定插入位置时,移动指针即可

3、栈

3.1、栈特点

  • 后进先出

3.2、算法基本思想

  • 可以用一个单链表来实现
  • 只关心上一次的操作
  • 处理完上一次的操作后,能在O(1)时间内查找到更前一次的操作

4、队列

4.1、队列特点

  • 先进先出

4.2、常用场景

  • 广度搜索

5、双端队列

5.1、常用场景

实现一个长度动态变化的窗口或者连续区间

6、树(重点掌握)

6.1、树的共性

  • 结构直观
  • 通过树问题来考察递归算法掌握的熟练程度

对于树的性质,往往要求每个节点都必须满足

  • 在定义二叉搜索树时,没个节点都必须是二叉搜索树
  • 求二叉树的深度

6.2、面试中常考的树的形状有

  • 普通二叉树
  • 平衡二叉树
  • 完全二叉树
  • 二叉搜索树

特殊的树:红黑树(不要了解)

6.3、常考

遍历(递归与非递归写法)

  • 前序 遍历(在树里搜索,以及创建一颗新的数用到)
  • 中序遍历(二叉搜索树,此时访问到的顺序就是元素的顺序)
  • 后序遍历 (当需要修改左右子节点,修改叶子节点时,收集的信息从底部到跟时)

leetcode基本数据结构之链表刷题分析_第1张图片

7、优先队列

(实现比较繁琐,在解决面试哦中的问题时,实行拿来主义即可)

本质

二叉堆的结构,利用一个数组结构来实现完全二叉树

leetcode基本数据结构之链表刷题分析_第2张图片

leetcode基本数据结构之链表刷题分析_第3张图片

基本操作

  • 向上筛选
  • 向下筛选

`时间复杂度:O(logk)

另一个重要的时间复杂度:优先队列的初始化 时间复杂度o(n)

特点

与普通队列的区别

保证每次取出的元素是队列中优先级最高的

优先级别可自定义

最常用的场景

从杂乱无章的数据中按照一定的顺序(或者优先级)筛选数据

	* 给定一个数组,找到前k个大的数
	* 求前k个高频元素
	* 关键如何定义优先级

8、图

leetcode基本数据结构之链表刷题分析_第4张图片

leetcode基本数据结构之链表刷题分析_第5张图片

9、前缀树

leetcode基本数据结构之链表刷题分析_第6张图片

leetcode基本数据结构之链表刷题分析_第7张图片

10、线段树

leetcode基本数据结构之链表刷题分析_第8张图片

11、树状数组

leetcode基本数据结构之链表刷题分析_第9张图片

你可能感兴趣的:(leetcode刷题笔记)