203.移除链表元素
这个题目之前做过一次,也通过了,今天二刷以为可以秒A。结果搞了半天还是报空指针异常,今天好好梳理一下:
1、首先,删除链表中的一个节点,为了不影响head节点,我们要定义一个curNode节点。当curNode的下一个节点的值是val的时候,就将curNode.next赋值为curNode.next.next,java会自动回收这个跳过的节点,如图(b)所示。
2、但是,如果要删除的节点是头结点,如图(a)所示,对于头结点来说,需要加一个虚拟节点作为它的curNode,这样才可以和图(b)一样通过curNode.next赋值为curNode.next.next来跳过这个需要删除的节点。
3、其次,我们每次都要判断curNode.next的val是不是要删除的val,所以curNode.next不能是null,while的循环条件应该是curNode.next != null。如图©当curNode.val=1的时候就必须要停止了。
所以代码为:
/**
* 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 dummyNode = new ListNode();
dummyNode.next = head;
ListNode curNode = dummyNode;
while(curNode.next != null){
if(curNode.next.val == val){
curNode.next = curNode.next.next;//如果下一个节点的val为目标val,就跳过下一个节点,curNode.next指向curNode.next.next。
}else{
curNode = curNode.next;//如果不是目标val,cuNode向下移动一位即可
}
}
return dummyNode.next;
}
}
206.反转链表
这道题最核心的地方在于要搞清楚每一个节点的next的方向是如何由向后变成向前的。下面一步一步说明:
首先定义一个pre节点和一个cur节点,因为cur最终作为尾节点要指向null,所以pre要先定义为null
下面我们要将cur的next换为pre,那么就会和后面的链表断开连接,因此要备份cur.next,定义为temp
cur.next改为前一个的pre节点
我们的pre和cur都需要向下移动一位,以控制后面的节点换方向。但是必须pre先向下移动,因为如果cur先想下变为temp的话,pre就无法再找到cur的位置了
pre往下移动一位之后,cur再往下移动一位
这个时候和上一个循环一样,要先备份temp,继续循环
。。。。。
那么当什么时候停止循环呢? 其实当cur为null的时候就可以停止了,因为这个时候cur为null,不需要再让cur指向pre操作了,这个时候就可以停止了,因此while循环的判断条件为while(cur != null)。
代码非常简洁,如下:
/**
* 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 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;
}
}
707.设计链表
这道题目需要定义一个全局变量链表的节点数length,增加节点的时候++,删除的时候–。
另外根据题意addAtIndex方法中,如果 index 比长度更大,该节点将不会插入 到链表中。需要判断一下index和length的大小,注意这里当index = length时,就直接将节点接到链表的尾部,当index>length时,直接return。
还有一个注意点是:我们可以先写addAtIndex方法,再写addAtHead和addAtTail方法,直接调用addAtIndex方法即可。注意这俩方法调用addAtIndex方法之后不需要再lenght++,因为addAtIndex中有length++了。
代码如下:
class MyLinkedList {
int length = 0;
ListNode dummyNode;
public MyLinkedList() {
dummyNode = new ListNode();
}
public int get(int index) {
if(index >= length) return -1;
ListNode cur = dummyNode;
for(int i = 0;i < index;i++){
cur = cur.next;
}
return cur.next.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);//这里调用了addAtIndex方法,里面就已经length++了,所以就不需要再length++了
}
public void addAtTail(int val) {
// ListNode newNode = new ListNode(val,null);
// ListNode curNode = dummyNode;
// while(curNode.next != null){
// curNode = curNode.next;
// }
// curNode.next = newNode;
// length++;
addAtIndex(length,val);
}
public void addAtIndex(int index, int val) {
if(index > length) return;
ListNode cur = dummyNode;
for(int i=0;i < index;i++){
cur = cur.next;
}
ListNode newNode = new ListNode(val,null);
if(cur.next == null){
cur.next = newNode;
}//在没有节点或者在最后一个节点插入的情况下
else{
ListNode temp = cur.next;
cur.next = newNode;
newNode.next = temp;
}
length++;
}
public void deleteAtIndex(int index) {
if(index >= length) return;
ListNode cur = dummyNode;
for(int i = 0;i < index;i++){
cur = cur.next;
}
if(index == length-1) cur.next = null;
else{
cur.next = cur.next.next;
}
length--;
}
}
class ListNode{
int val;
ListNode next;
ListNode(){}
ListNode(int val,ListNode next){
this.val = val;
this.next = next;
}
}
/**
* 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);
*/