(1)单链表:每个节点由数据域与指针域组成{data,next}
(2)双链表:每个节点由数据域及指针域(两个指针)组成{data,pre,next}
(3)循环链表:节点结构与单链表一致,但是首尾相连
题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/
分析:经典链表操作,主要需要考虑两种场景
解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;
}
}
题目链接: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;
}
}
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;
}
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);
}
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;
}
总结:在添加虚拟头节点后,主要需要注意 合法范围、边界点的处理,还有就是添加到是很好语句顺序不能颠倒;明天补充学习用双向链表的题解
题目链接:https://leetcode.cn/problems/reverse-linked-list/description/
题目分析:使用双指针链表思想实现翻转,大致步骤如下
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