目录
203.移除链表元素(虚拟头结点)
解题分析
正常删除需考虑两种情况,若删除的为头结点,将头结点向后移动一位;若删除的为非头结点,则让需删除节点的前一节点指向next的next。
为了简化,考虑虚拟头节点方法,让该虚拟节点指向头结点,然后就可以对所有节点一视同仁的操作,不用单独考虑头结点了。最后return 头结点是 return dummyNode->next;
这才是原本的头结点。
本题代码
/**
* Definition for singly-linked list.
* 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; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode current = dummy; // 为了避免改变链表,单独定义一个节点
while(current.next != null){
if(current.next.val == val){
current.next = current.next.next; //找到val,为current.next,删除该节点
}else{
current = current.next; //没找到val,current移向下一节点
}
}
return dummy.next;
}
}
707.设计链表(虚拟头结点)
题目链接:https://leetcode.cn/problems/design-linked-list/description/
解题分析(该题有5个常见链表操作,需熟悉掌握)
该题可用虚拟头节点方法。
首先定义一个节点类ListNode,它包含一个整数值val、一个指向下一个节点的引用next。
初始化时,MyLinkedList类中创建dummyHead(虚拟头结点) 和 size(存储链表元素个数),在MyLinkedList构造器中进行初始化。
-
获取第n(index)个节点的val
实现 get(int index) 时,先判断有效性,再通过循环来找到对应的节点的值。
有效性:index取值为0到size-1,所以 index < 0 || index >= size,返回 -1;
循环: for循环遍历寻找index节点,注意边界条件,可用头结点index=0代入试判断,返回index.val。
-
插入头结点
注意插入节点时,第一步和第二步顺序不能搞反!
-
插入尾结点
-
插入n(index)节点前
要知道插入节点的前一指针,才能插入节点,所以cur在index的前一位置。
-
删除n(index)节点
cur在index的前一位置,即第index节点一定是cur.next。
本题代码
class MyLinkedList {
class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
}
}
private int size;
private ListNode dummyHead;
//初始化链表
public MyLinkedList() {
size = 0;
dummyHead = new ListNode(0);
}
//获取第index节点的val
public int get(int index) {
if(index < 0 || index >= size){
return -1;
}
ListNode cur = dummyHead.next;
for(int i = 0; i < index; i++){
cur = cur.next;
}
return cur.val;
}
//插头结点
public void addAtHead(int val) {
ListNode newNode = new ListNode(val);
newNode.next = dummyHead.next; //第一步!
dummyHead.next = newNode; //第二步!
size++;
}
//插尾结点
public void addAtTail(int val) {
ListNode newNode = new ListNode(val); //1.创建新节点
ListNode cur = dummyHead; //2.cur位置在尾结点处
while(cur.next != null){
cur = cur.next;
}
cur.next = newNode; //3.插入尾节点
size++; //长度加1
}
//插入第index节点前
public void addAtIndex(int index, int val) {
if(index < 0 || index > size){ //1.判断角标有效性,注意是>size!,因为等于size时是在尾结点指向的null处,null前依然可以插入节点
return;
}
ListNode newNode = new ListNode(val); //2.创建新节点
ListNode cur = dummyHead; //3.cur位置在index前一节点
for(int i = 0; i < index; i++){
cur = cur.next;
}
/*while(index > 0){
cur = cur.next;
index--;
} */
newNode.next = cur.next; //4.插入节点
cur.next = newNode;
size++; //5.长度加1
}
//删除第index节点
public void deleteAtIndex(int index) {
if(index < 0 || index >= size){ //1.判断角标有效性
return;
}
ListNode cur = dummyHead; //2.cur位置在index前一节点
for(int i = 0; i < index; i++){
cur = cur.next;
}
cur.next = cur.next.next; //3.删除节点
size--; //4.长度减1
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
206.反转链表
题目链接:https://leetcode.cn/problems/reverse-linked-list/description/
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
解题分析
本题优先考虑双指针法,更易理解,熟练后可用递归法。
本题代码
-
双指针法
令cur为头结点;
pre为cur的前一节点,值为null;
temp为cur的下一节点,作用是保存位置,避免改变方向链表断开,无法找到cur的下一节点位置。
链表从头开始遍历,终止条件是cur为null。先用temp保存cur.next位置;然后改变cur方向,指向pre;再令cur和pre节点后移一位;最后返回头节点位置pre。
//双指针法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
ListNode temp = null; //保存位置的节点
while(cur != null){ //终止条件是cur为null,pre为头节点
temp = cur.next; // 1.保存下一节点
cur.next = pre; // 2.更改cur方向
pre = cur; // 3.pre移向下一节点
cur = temp; // cur移向下一节点
}
return pre; //pre为头结点
}
}
-
递归法
与双指针大体逻辑相同
// 递归
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode prev, ListNode cur) {
if (cur == null) {
return prev;
}
ListNode temp = null;
temp = cur.next;// 先保存下一个节点
cur.next = prev;// 反转
// 更新prev、cur位置
// prev = cur;
// cur = temp;
return reverse(cur, temp);
}
}