一、移除链表元素
解题思路
有两种方法,第一种是在原链表中进行移除操作,第二种是设置一个虚拟头节点进行操作。
本次我采用的是第二种方法。
给链表添加一个新的节点作为头结点,有利于后续节点移除的统一处理。
代码如下:
class Solution {
public ListNode removeElements(ListNode head, int val) {
//新建一个节点
ListNode dummyhead=new ListNode();
//让该指针指向原链表的头节点,形成虚拟头结点
dummyhead.next=head;
/*
使用cur记录当前遍历的节点
因为最后需要返回原链表,所以不能直接操作dummyhead,否则会导致虽然移除了元素,
但是由于dummyhead发生了改变,无法通过dummyhead返回原链表
*/
ListNode cur=dummyhead;
/*
在链表中移除一个节点时需要知道该节点的前一个节点才能进行操作,
所以在这里cur代表被移除节点的前一个节点,
cur.next才是我们真正要移除的元素
*/
while(cur.next!=null){
if(cur.next.val==val){
cur.next=cur.next.next;
}
else {
cur=cur.next;
}
}
return dummyhead.next;
}
}
二、设计链表
解题思路
这道题是对链表操作的综合考察,要求我们实现以下几个函数:
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
分析:
(1)首先设计一个单链表。
(2)get函数:判断index是否合法,不合法则退出;合法使用for循环进行查找,最后返回相应节点的值。
(3)addAtHead(val):根据要求分析可知,该函数要求在head后添加一个新节点。
具体做法如下:A.创建一个值为val的新节点newNode。
B.newNode的下一个结点指向head的下一个节点。
C.head的下一个结点指向newNode。
D.链表整体长度size+1。
按顺序执行A~D步骤。
(4)addAtTail(val):首先通过cur遍历到链表尾部,然后在尾部进行插入操作。
(5)addAtIndex(index,val):
首先判断index是否合法,如果大于size ,不合法,return;如果小于0,就将该节点插入到链表头部。如果index在[0,size)区间,对链表遍历直至index的前一个节点,然后进行插入操作。
(6)deleteAtIndex(index):
如果index合法则遍历链表找到index的前一个结点,然后进行删除操作。
整体代码如下:
class ListNode {
int val;
ListNode next;
ListNode(){};
ListNode(int val){
this.val=val;
}
}
class MyLinkedList {
int size;
ListNode head;
//初始化链表
public MyLinkedList() {
size=0;
head=new ListNode(0);
}
//获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
public int get(int index) {
if(index<0 || index>=size){
return -1;
}
ListNode cur=head;
for(int i=0;i<=index;i++){
cur=cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
ListNode h=new ListNode(val);
ListNode cur=head;
h.next=cur.next;
cur.next=h;
size++;
}
public void addAtTail(int val) {
ListNode t=new ListNode(val);
ListNode cur=head;
while(cur.next!=null){
cur=cur.next;
}
cur.next=t;
size++;
}
// 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果 index 大于链表的长度,则返回空
public void addAtIndex(int index, int val) {
if(index>size)
return;
if(index<=0)
index=0;
ListNode n=new ListNode(val);
ListNode cur=head;
for(int i=0;i<index;i++){
cur=cur.next;
}
n.next=cur.next;
cur.next=n;
size++;
}
//删除第index个节点
public void deleteAtIndex(int index) {
if(index<0 || index>=size){
return;
}
size--;
ListNode cur=head;
for(int i=0;i<index;i++){
cur=cur.next;
}
cur.next=cur.next.next;
}
}
三、反转链表
解题思路
本题可以通过改变链表的next指针指向实现反转。
代码如下:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre=null,cur=head;
while(cur!=null){
ListNode nxt=cur.next;
cur.next=pre;
pre=cur;
cur=nxt;
}
return pre;
}
}
四、今日收获
重温了链表基础理论知识并练习了链表的增删改查等操作。对于链表节点的next的概念及使用有了更为深刻的认识与理解。今日学习+解题+博客=2h30min。
此为个人学习记录所用,难免有不妥之处。若各位大佬发现文章错误之处,或有更好的方法,烦请指正,谢谢。