203.移除链表元素
建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
以下是用虚拟节点dummy的版本,
- 时间复杂度 O(n)
- 空间复杂度 O(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) {
//链表没东西时候返回链表
if(head==null){return head;}
ListNode dummy=new ListNode(-1,head);
// cur和pre都是指针
ListNode pre=dummy;
ListNode cur=head;
//while里面用cur或者pre.next都可以
while(cur!=null){
if(cur.val==val){
pre.next=cur.next;
}else{
pre=cur;
}
cur=cur.next;
}
return dummy.next;
}
}
707这道题目设计链表的五个接口:
获取链表第index个节点的数值
在链表的最前面插入一个节点
在链表的最后面插入一个节点
在链表第index个节点前面插入一个节点
删除链表的第index个节点
可以说这五个接口,已经覆盖了链表的常见操作,是练习链表操作非常好的一道题目
链表操作的方式:
设置一个虚拟头结点在进行操作。
public class MyLinkedList {
// Definition of the linked list node class
private class ListNode {
int val;
ListNode next;
// Node constructor
ListNode(int val) {
this.val = val;
this.next = null;
}
}
private int size;
private ListNode dummyHead;
// Constructor initializes the linked list
public MyLinkedList() {
this.dummyHead = new ListNode(0); // Dummy head node
this.size = 0;
}
// Get the value of the index-th node in the linked list
public int get(int index) {
if (index < 0 || index >= this.size) {
return -1;
}
ListNode cur = this.dummyHead.next;
while (index > 0) {
cur = cur.next;
index--;
}
return cur.val;
}
// Add a node at the head of the linked list
public void addAtHead(int val) {
addAtIndex(0, val);
}
// Append a node at the tail of the linked list
public void addAtTail(int val) {
addAtIndex(this.size, val);
}
// Add a node with value `val` before the index-th node in the linked list
public void addAtIndex(int index, int val) {
if (index > this.size) {
return;
}
if (index < 0) {
index = 0;
}
this.size++;
ListNode pred = this.dummyHead;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode newNode = new ListNode(val);
newNode.next = pred.next;
pred.next = newNode;
}
// Delete the index-th node in the linked list, if the index is valid
public void deleteAtIndex(int index) {
if (index < 0 || index >= this.size) {
return;
}
this.size--;
ListNode pred = this.dummyHead;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
// Print the linked list
public void printLinkedList() {
ListNode cur = this.dummyHead;
while (cur.next != null) {
System.out.print(cur.next.val + " ");
cur = cur.next;
}
System.out.println();
}
}
206.反转链表
双指针:
时间复杂度: O(n)
空间复杂度: O(1)
动图看https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC
/**
* 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;//这是双链表的头节点的现指针
ListNode temp=null;
while(cur!=null){//当cur指到null时候,pre也到了最后一个节点
temp=cur.next;
cur.next=pre;
//pre和cur都继续往后走了;
pre=cur;
cur=temp;
}
return pre;
}
}
递归法,是基于双指针基础上的。
时间复杂度: O(n), 要递归处理链表的每个节点
空间复杂度: O(n), 递归调用了 n 层栈空间
/**
* 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) {
return reverse(null,head);}
private ListNode reverse(ListNode pre,ListNode cur){
if(cur==null){
return pre;
}
ListNode temp=null;
temp=cur.next;//保存下一个节点
cur.next=pre;//然后反转
return reverse(cur,temp);//然后往后递归,这时候前驱节点和后继节点都右移了一位。
}
}