目录
1.203. 移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == 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
输出:[]
提示:
列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50
1.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 ans = null;
//分类讨论:头元素,非头元素
while (head != null && head.val == val) {
head = head.next;
}
ans = head;
if(ans ==null){
return ans;
}
ListNode cur = ans;
while (cur != null && cur.next != null) {
if (cur.next.val == val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return ans;
}
}
1.2 新增一个头节点,判断next节点的val
思路:新增虚拟头结点,就可以将所有节点当成非头结点进行处理,不用分类处理。
/**
* 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 ans = null;
// 新增一个头节点
ListNode per = new ListNode(-1, head);
ListNode cur = per;
while (cur.next != null) {
if (cur.next.val == val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return per.next;
}
}
1.3 新增一个头节点,判断当前节点的val
/**
* 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 ans = null;
// 新增一个头节点
ListNode per = new ListNode(-1, head);
ListNode dummy = per;
ListNode cur = per.next;
while (cur != null) {
if (cur.val == val) {
//相等 cur后移,per不移,per的next下移
per.next = cur.next;
} else {
//不相等 per和cur都下移
per = per.next;//或per=cur
}
cur = cur.next;
}
return dummy.next;
}
}
2. 707. 设计链表
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList 类:
- MyLinkedList() 初始化 MyLinkedList 对象。
- int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
- void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
- void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
- void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
- void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。
示例:
输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 3
提示:
0 <= index, val <= 1000
请不要使用内置的 LinkedList 库。
调用 get、addAtHead、addAtTail、addAtIndex 和 deleteAtIndex 的次数不超过 2000 。
2.1 单向链表
过程:一开始看题目一点思路都没有,看了下代码随想录思路后,自己写出代码加debug后通过。
题目意义:单向链表的基础应用
class MyLinkedList {
ListNode dummyHead;
int size;
class ListNode {
int val;
ListNode next;
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public MyLinkedList() {
dummyHead = new ListNode(0);
size = 0;
}
public int get(int index) {
if (index > size - 1 || index < 0) {
return -1;
}
ListNode cur = dummyHead;
while (index > 0) {
cur = cur.next;
index--;
}
return cur.next.val;
}
public void addAtHead(int val) {
ListNode tmp = dummyHead.next;
dummyHead.next = new ListNode(val, tmp);
size++;
}
public void addAtTail(int val) {
ListNode cur = dummyHead;
while (cur.next != null) {
cur = cur.next;
}
cur.next = new ListNode(val);
size++;
}
public void addAtIndex(int index, int val) {
if (index > size || index < 0) {
return;
}
ListNode cur = dummyHead;
while (index > 0) {
cur = cur.next;
index--;
}
ListNode tmp = cur.next;
cur.next = new ListNode(val, tmp);
size++;
}
public void deleteAtIndex(int index) {
if (index > size - 1 || index < 0) {
return;
}
ListNode cur = dummyHead;
while (index > 0) {
cur = cur.next;
index--;
}
ListNode tmp = cur.next.next;
cur.next = tmp;
size--;
}
}
/**
* 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);
*/
3. 206. 反转链表
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2:
输入:head = [1,2] 输出:[2,1]示例 3:
输入:head = [] 输出:[]提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
过程:先写的循序,然后看也可以递归,但递归写成跟循环一样的逻辑 。
3.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 reverseList(ListNode head) {
// 当前已处理的链的上一个节点
ListNode per = new ListNode(-1, null);
// 剩下未处理的链
ListNode first = head;
ListNode cur = per;
while (first != null) {
// 下一次剩下需处理的链
ListNode tmp = first.next;
// 指向已处理好的链的首节点
first.next = per.next;
per.next = first;
first = tmp;
}
return per.next;
}
}
3.2 递归,新增头结点,从前往后处理
逻辑跟3.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 reverseList(ListNode head) {
// 当前已处理的链的上一个节点
ListNode per = new ListNode(-1, null);
deal(per, head);
return per.next;
}
public void deal(ListNode per, ListNode head) {
// 终止条件
if (head == null) {
return;
}
// 单层逻辑
ListNode tmp = head.next;
head.next = per.next;
per.next = head;
head = tmp;
// 递归
deal(per, head);
}
}
3.3 递归,不新增头结点,从前往后处理
/**
* 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 deal(null, head);
}
// 确定参数及返回值
// 参数:已处理好的链,未处理的链
// 返回值:已处理好的链
public ListNode deal(ListNode per, ListNode head) {
// 终止条件
if (head == null) {
return per;
}
// 单层逻辑
// 下次需待处理的链
ListNode tmp = head.next;
// 当前节点指向已处理好的链
head.next = per;
// 递归
return deal(head, tmp);
}
}
3.4 递归,从后往前处理
/**
* 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 {
// 递归
// 1、确定参数和返回值
// 参数:待处理的链
// 返回值已处理的链
public ListNode reverseList(ListNode head) {
// 2终止条件
if (head == null || head.next == null) {
return head;
}
// 递归
//返回的就是最后一个节点
ListNode node = reverseList(head.next);
// 单层逻辑 从最后两个节点进行处理
head.next.next = head;
head.next = null;
return node;
}
}