LeetCode 203.移除链表元素
题目链接:https://leetcode.cn/problems/remove-linked-list-elements/
思路:
1)递归:对除了头节点 head以外的节点进行删除操作,然后判断 head的节点值是否等于给定的 val。如果 head的节点值等于 val,则 head需要被删除,因此删除操作后的头节点为 head.next;如果head的节点值不等于 val,则head保留,因此删除操作后的头节点还是head。
2)迭代:设置一个虚拟头dummyHead结点再进行删除操作,此时可以把头结点和非头结点归为一类进行操作(若直接使用原来的链表来进行删除操作,此时需要头结点和非头结点分开操作)。具体操作为:遍历链表,用cur表示当前节点。如果cur的下一个节点不为空且下一个节点的节点值等于给定的 val,则需要删除下一个节点。
代码1:
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null)
return head;
head.next = removeElements(head.next,val);
return head.val == val ? head.next : head;
}
}
代码2:
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode cur = dummyHead;
while (cur.next != null) {
if (cur.next.val != val) {
cur = cur.next;
} else {
cur.next = cur.next.next;
}
}
return dummyHead.next;
}
}
LeetCode 707.设计链表
题目链接:https://leetcode.cn/problems/design-linked-list/
思路1:对于单链表,定义的头结点head是一个虚拟头结点,而不是真正的链表头结点。 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点。在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点;如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点;如果index大于链表的长度,则返回空;如果index小于0,则置为0,作为链表的新头节点。
代码1:
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size = 0;
head = new ListNode();
}
public int get(int index) {
if(index < 0 || index > size-1)
return -1;
ListNode cur = head;
for(int i = 0; i <= index; i++){
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size,val);
}
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 newNode = new ListNode(val);
newNode.next = cur.next;
cur.next = newNode;
}
public void deleteAtIndex(int index) {
if(index < 0 || index > size-1)
return;
size--;
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
cur.next = cur.next.next;
}
}
思路2:双链表
代码2:
//双链表
class ListNode{
int val;
ListNode next,prev;
ListNode() {};
ListNode(int val){
this.val = val;
}
}
class MyLinkedList {
//记录链表中元素的数量
int size;
//记录链表的虚拟头结点和尾结点
ListNode head,tail;
public MyLinkedList() {
//初始化操作
this.size = 0;
this.head = new ListNode(0);
this.tail = new ListNode(0);
//这一步非常关键,否则在加入头结点的操作中会出现null.next的错误!!!
head.next=tail;
tail.prev=head;
}
public int get(int index) {
//判断index是否有效
if(index<0 || index>=size){
return -1;
}
ListNode cur = this.head;
//判断是哪一边遍历时间更短
if(index >= size / 2){
//tail开始
cur = tail;
for(int i=0; i< size-index; i++){
cur = cur.prev;
}
}else{
for(int i=0; i<= index; i++){
cur = cur.next;
}
}
return cur.val;
}
public void addAtHead(int val) {
//等价于在第0个元素前添加
addAtIndex(0,val);
}
public void addAtTail(int val) {
//等价于在最后一个元素(null)前添加
addAtIndex(size,val);
}
public void addAtIndex(int index, int val) {
//index大于链表长度
if(index>size){
return;
}
//index小于0
if(index<0){
index = 0;
}
size++;
//找到前驱
ListNode pre = this.head;
for(int i=0; i<index; i++){
pre = pre.next;
}
//新建结点
ListNode newNode = new ListNode(val);
newNode.next = pre.next;
pre.next.prev = newNode;
newNode.prev = pre;
pre.next = newNode;
}
public void deleteAtIndex(int index) {
//判断索引是否有效
if(index<0 || index>=size){
return;
}
//删除操作
size--;
ListNode pre = this.head;
for(int i=0; i<index; i++){
pre = pre.next;
}
pre.next.next.prev = pre;
pre.next = pre.next.next;
}
}
LeetCode 206.反转链表
题目链接:https://leetcode.cn/problems/reverse-linked-list/
思路:
1)迭代:在遍历链表时,将当前节点的 next指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。
2)递归:递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。
代码:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
while(cur != null){
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}