Code03_链表理论基础_203.移除链表元素_707.设计链表_206.反转链表
203.移除链表元素
题意:删除链表中等于给定值 val 的所有节点。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
思路
为了保证删除的统一逻辑,在这里使用了虚拟头结点的方式,也就是在头结点之前加一个虚拟的头结点,这样在删除节点的时候就不需要区分,是否为头结点
这里来给链表添加一个虚拟头结点为新的头结点,此时要移除这个旧头结点元素1。
这样是不是就可以使用和移除链表其他节点的方式统一了呢?
来看一下,如何移除元素1 呢,还是熟悉的方式,然后从内存中删除元素1。
最后呢在题目中,return 头结点的时候,别忘了 return dummyNode->next;
, 这才是新的头结点,因为原来的头结点可能已经删掉了
class Solution {
/* public ListNode removeElements(ListNode head, int val) {
//不添加虚拟头结点
while(head != null && head.val == val){//要删除的节点是头结点的情况
head = head.next;
}
ListNode curr = head;//curr用来遍历链表
while(curr != null){//当前链表不为空
while(curr.next != null && curr.next.val == val){//要删除的节点不是头结点的情况
curr.next = curr.next.next;//剔除中间的元素
}
curr = curr.next;//继续遍历
}
return head;
} */
public ListNode removeElements(ListNode head, int val) {
//添加虚拟头结点
// if (head == null) {
// return head;
// }
ListNode dummy = new ListNode(-1,head);//新生成一个虚拟头结点,并将next指向头结点
ListNode cur = dummy; //cur用来遍历,dummy是当前的头结点,从dummy开始遍历
while(cur.next != null){
if(cur.next.val == val){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
head = dummy.next;
return head;
}
}
707.设计链表
题意:
在链表类中实现这些功能:
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
思路
关键是各种边界、next等细节的处理,这题值得细看,但是碍于精力有限,值得仔细回味
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 MyLinkedList {
int size;
ListNode head;//虚拟头结点
public MyLinkedList() {
size = 0;
head = new ListNode(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 int get(int index) {
//如果index非法,返回-1
if (index < 0 || index >= size) {
return -1;
}
ListNode currentNode = head;
//包含一个虚拟头节点,所以查找第 index+1 个节点
for (int i = 0; i <= index; i++) {
currentNode = currentNode.next;
}
return currentNode.val;
}
// public void addAtHead(int val) {
// ListNode NewHead = new ListNode(val,head);
// head.next = NewHead;
// size++;
// }
// public void addAtTail(int val) {
// ListNode tail = new ListNode(val,null);
// ListNode cur = head;
// for(int i = 0; i <= size; i++){
// cur = cur.next;
// }
// cur.next = tail;
// size++;
// }
//在链表最前面插入一个节点,等价于在第0个元素前添加
public void addAtHead(int val) {
addAtIndex(0, val);
}
//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
public void addAtTail(int val) {
addAtIndex(size, val);
}
// public void addAtIndex(int index, int val) {
// if(index <= 0){
// index = 0;
// addAtHead(val);
// }
// else if(index == size){
// addAtTail(val);
// }
// else if(index > size) {
// return;
// }
// else{
// ListNode cur = head;
// for(int i = 0; i <= index; i++){
// cur = cur.next;
// }
// ListNode NewNode = new ListNode(val,cur.next);
// cur.next = NewNode;
// size++;
// }
// }
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
if (index < 0) {
index = 0;
}
size++;
//
ListNode cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = cur.next;
cur.next = toAdd;
}
// public void deleteAtIndex(int index) {
// }
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
if (index == 0) {
head = head.next;
return;
}
ListNode cur = head;
for (int i = 0; i < index ; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
}
}
206.反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
思路
关键是改变原来链表里的指向,而不是新链表的指向
关键是改变原来链表里的指向,而不是新链表的指向,所以重要的是要改变cur.next
,所以要用tmp做一个暂存,因为接下来这个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 reverseList(ListNode head) {
ListNode cur = head;
ListNode newhead = null;
ListNode tmp = null;
//关键是改变原来链表的指向,因此关键是改变原链表的next,
while(cur != null) {
tmp = cur.next;//保存原来链表的下一个节点
cur.next = newhead;// 改变当前节点的下一个指向
newhead = cur;//更新头结点
cur = tmp;//此时不能用cur.next了 因为cur.next已经指向新的头结点了
}
return newhead;
}
}
// class Solution {
// public ListNode reverseList(ListNode head) {
// ListNode newhead = null;
// ListNode cur = head;
// ListNode temp = null;
// while (cur != null) {
// temp = cur.next;// 保存下一个节点
// cur.next = newhead;
// newhead = cur;
// cur = temp;
// }
// return newhead;
// }
// }