1.基础知识——链表
- 是由指针串联在一起的线性结构
- 分类:
(1)单链表:每个节点由数据域与指针域组成{data,next}
(2)双链表:每个节点由数据域及指针域(两个指针)组成{data,pre,next}
(3)循环链表:节点结构与单链表一致,但是首尾相连
- 存储:内存分布不是连续的
- 链表定义代码※
- 链表优点在于长度不固定,能够实现动态增删,适用于 增删频繁但是查询频率比较低的情景
Leetcode203.移除链表元素
题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/
分析:经典链表操作,主要需要考虑两种场景
- 当前节点为头节点,满足条件需要删除此元素: head = head.next
- 不为头节点,满足条件需要删除此元素 :node.next = node.next.next(此处表示对node是需要删除节点的前一个节点)
解1:Java正常删除节点法
class Solution {
public ListNode removeElements(ListNode head, int val) {
while((head!=null)&&(head.val == val)){
//直到找到一个不等于val的节点值,作为头节点
head=head.next;
}
ListNode nownode = head;
while((nownode != null)&&(nownode.next != null)){
//第一个null 指空链表
//第二个null 指遍历到链表末端的结束标志
if(nownode.next.val==val){
nownode.next = nownode.next.next;
}else{
nownode = nownode.next;
}
}
return head;
}
}
解2:Java自创方法-如果头节点为需要删除的值,最后处理,代码如下:
class Solution {
public ListNode removeElements(ListNode head, int val) {
boolean headvalflag = false;
if(head == null){
return head;
}else if(head.val == val){headvalflag =true;}
ListNode nownode = head;
while(nownode.next!=null){
if(nownode.next.val == val){
nownode.next = nownode.next.next;
}else{
nownode = nownode.next;
}
}
if(headvalflag == true){
return head.next;
}else{
return head;
}
}
}
解3:Java构建虚拟头节点,统一后续操作(比较推荐)-画了个图示,如下:
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode virtuallyHeadNode = new ListNode(val+1,head);
//此处虚拟节点的数据可以随机取,没有影响
ListNode nownode = virtuallyHeadNode;
while(nownode.next != null){
if(nownode.next.val == val){
nownode.next = nownode.next.next;
}else{
nownode = nownode.next;
}
}
return virtuallyHeadNode.next;
}
}
Leetcode.707设计链表
题目链接:https://leetcode.cn/problems/design-linked-list/description/
题目分析:设计链表实现以下几个函数:(使用添加虚头节点方式实现简化以下操作)
类成员定义,构造函数
//java节点的实现类
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next;
}
//MyLinkedList 类内属性及构造函数
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
this.head = new ListNode(0);
size = 0;
}
}
- get(index):根据索引获得元素
- 分析:要分为合法与不合法情况,不合法返回-1,合法返回对应索引处的值
-
public int get(int index) { //非法: //index(max) = size-1;索引size处取不到 //index(min) = 0; if((index<0)||(index>=size)){ return -1; } //获取head节点;----thesizeIndex=0 ListNode currentN = head; //获取index处 节点----thesizeIndex=index+1 for (int i = 0; i <= index; i++) { currentN = currentN.next; } return currentN.val; }
- add: addAtHead(val) 在头部添加 ;addAtTail(val) 在尾部添加;addAtIndex(index,val)在index索引前添加
- 分析:将三个add方法均看作为一个方法
- index = 0头部插入 addAtTail(val)
- index = size尾部插入 addAtTail(val)
- 0<index<size 正常插入
- index<0 或者 index>size 为不合法范围
-
public void addAtIndex(int index, int val) { //不合法范围 if (index > size) { return; } if (index < 0) { index = 0; } //找index-1位置元素---sizeindexI = index; //sizeindexI = 0; ListNode pred = head; //如果在头部,就不进入for循环 //sizeindexI = index; index-1 for (int i = 0; i < index; i++) { pred = pred.next; } //连接 ListNode toAdd = new ListNode(val); toAdd.next = pred.next;//如果在尾部的时候,pred.next =null pred.next = toAdd; size++; }
public void addAtHead(int val) { addAtIndex(0, val); } public void addAtTail(int val) { addAtIndex(size, val); }
- deleteAtIndex(index) 删除对应索引处元素
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
//如果删除的是头节点,直接执行
if (index == 0) {
head = head.next;
return;
}
//非头节点 找到index-1 sizeIndexI=index;
//sizeIndexI=0;
ListNode pred = head;
//sizeIndexI=index;
for (int i = 0; i < index ; i++) {
pred = pred.next;
}
//删除
pred.next = pred.next.next;
}
总结:在添加虚拟头节点后,主要需要注意 合法范围、边界点的处理,还有就是添加到是很好语句顺序不能颠倒;明天补充学习用双向链表的题解
Leetcode206.链表翻转
题目链接:https://leetcode.cn/problems/reverse-linked-list/description/
题目分析:使用双指针链表思想实现翻转,大致步骤如下
- 初始化ListNode pre、cur 分别为null 、head
- 取cur.next 的值,存为临时变量,放置后面cur-》pre时失去连接;temp = cur.next
- cur,pre移动:先移动pre pre = cur; 再移动 cur cur = temp;(如果先移动cur temp会无法找到前一个cur,失去连接)
- tips:终止条件 pre指向最后一个元素即新的head,此时 cur也就指向了NULL;
- 故返回到条件是 pre(head)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
总结:206,203两题思路比较清晰,但是707再写还是很混乱在边界点处 size 与 index关系容易判断不好,还需要再练,明天要把707双向链表的题解消化实现,还有就是206链表翻转 还可以使用递归的方法实现,听了一次视频讲解还是很晕,明天梳理之后看看能不能理解,如果可以再补充实现代码。
视频链接我也放在下面了:https://www.bilibili.com/video/BV1nB4y1i7eL/?vd_source=83dc9f68f506e8a2be88d095001c1ba5