LeetCode 203 移除链表元素
本题思路:就是常规的移除链表中的元素的操作。需要注意的点:
- 头节点 head.val = val 的情况的处理,如果 head.val = val , 就要继续往后 head = head.next ,因此我们要遍历到第一个 head.val != val 的节点
- 如果遍历到最后,所有的节点的值都不等于 val,此时就直接返回 head;
- 如果遍历到最后,链表中还有元素。此时就开始做判断
class Solution {
public ListNode removeElements(ListNode head, int val) {
// 首先先判断极端情况
if(head == null){
return head;
}
// 如果不为空,就有可能头节点的值=val,所以要遍历到第一个不等于 val的节点
while(head != null && head.val == val){
head = head.next;
}
// 此时要么 head 为空了,要么 head.val!=val
// 定义两个指针,一个用来遍历,一个用来定位当前节点的前一个节点。
if(head == null){
return head;
}
ListNode pre = head;
ListNode cur = head.next;
while(cur!=null){
// 如果 cur.val == val,就要移除掉
if(cur.val == val){
pre.next = cur.next;
cur = cur.next;
}else{ // 如果不等于
pre = cur;
cur = cur.next;
}
}
return head;
}
}
下面我们利用示例中的样例,通过图文表示,来描述下这个过程,让思路更加的清晰。
- 此时的 head.val != val,就定义 pre = head , cur = head.next。
- 接下来就开始判断 cur 是否为空,cur.val 是否等于 val,此时 cur != null,并且 cur.val != val。 所以我们进行以下操作。cur = cur.next,pre = cur。
- 继续根据上图,开始做判断,此时 cur != null,并且 cur.val = val。所以我们要进行以下操作,将 pre.next = cur.next。cur = cur.next。
- 继续根据上图,开始做判断,此时 cur != null,并且 cur.val != val,所以我们进行以下操作,将 cur.next = next,pre = cur。
- 继续根据上图,开始做判断,此时 cur != null,并且 cur.val != val,所以我们进行以下操作,将 cur.next = next,pre = cur。
- 继续根据上图,开始做判断,此时 cur != null,并且 cur.val != val,所以我们进行以下操作,将 cur.next = next,pre = cur。
- 继续根据上图,开始做判断,此时 cur != null,并且 cur.val = val。所以我们要进行以下操作,将 pre.next = cur.next。cur = cur.next。
- 此时 cur = null, 退出循环。 返回 head。
LeetCode 707 设计链表
题目,让我设计一个链表,可以是单链表或者是双链表。此处我们就设计一个带有虚拟头节点的单链表。
- 获取链表第 index 个节点的值
- 在链表的最前面插入一个节点
- 在链表的末尾插入一个节点
- 在链表第index个节点前面插入一个节点
- 删除链表的第index个节点
public class MyLinkedList {
static class ListNode {
int val = 0;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
// 定义一个虚拟头节点
ListNode head;
int size = 0;
// 实现一个单链表, 带虚拟头节点的
public MyLinkedList() {
// 记录元素个数
head = new ListNode(0);
}
// 获取下标 index 节点的值
public int get(int index) {
ListNode currNode = head;
if (index < 0 || index >= size) {
return -1;
}
// index 满足条件
for(int i=0; i<=index;i++){
currNode = currNode.next;
}
return currNode.val;
}
// 头插
public void addAtHead(int val) {
addAtIndex(0,val);
}
// 尾插
public void addAtTail(int val) {
addAtIndex(size,val);
}
// 把值为 val的节点 追加到链表中下标为 index 的节点的前面
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
ListNode node = new ListNode(val);
ListNode currNode = head;
// 如果 index 等于链表长度,直接加到末尾
if (index < 0) {
index = 0;
}
// 找到要插入的节点的 前驱节点
while (index-- != 0) {
currNode = currNode.next;
}
node.next = currNode.next;
currNode.next = node;
size++;
}
// 如果下标有效,删除下标为 index 的节点
public void deleteAtIndex(int index) {
// 如果下标小于0,或者>=size,下标不符合
if (index < 0 || index >= size) {
return;
}
ListNode currNode = head;
// 找到要删除的下标 index 的前驱节点
while (index-- != 0) {
currNode = currNode.next;
}
currNode.next = currNode.next.next;
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);
*/
下图假设是链表的初始状态
下面一个一个分析这几个接口。
- addAtIndex(2, 5),在下标为 2 的节点前,插入一个值为 5 的节点。
- 首选找到 下标为 2 的节点的前驱节点下标为1的节点,可以看到 curNode移动了两次,就是 index的值 2
- 找到前驱节点 curNode,将 node.next = curNode.next,curNode.next = node ,此时 size+1=5
- deleteAtIndex(4) ,删除下标为 4 的节点。
- 首先还是找到下标为 4 的节点的前驱节点。可以看到 curNode 移动了4次,就是 index的值 4。
> 2. 然后让 curNode.next = curNode.next.next, size=size-1=4
- get(2),获取下标为 2 的节点值
- 下标为2,根据下图分析,那么要遍历 3 次,才能定位到 下标 2
- 找到后,直接返回这个节点的值即可。
- addAtHead(int val),在头插,就相当于在下标为 0 的地方插入,直接调用 addIndex(0,val) 即可
- AddTail(int val),在尾插,就当于在尾巴插入,直接调用 addIndex(size,val) 即可
LeetCode 206 反转链表
本题思路:反转单链表。我们可以使用双指针来解决这个问题,定义个 pre=null,定义一个 cur = head 用来遍历这个链表。还需要定义一个 tmp 来保存记录 cur 的记录,因为遍历过程中,cur.next 会往前指,所以要保留 cur 原先的 next 地址。
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode pre = null;
ListNode cur = head;
// 定义一个临时指针
ListNode tmp = null;
while(cur != null){
tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
下面用这个示例2,利用画图来一步一步分析步骤。
-
首先初始状态如下在这里插入图片描述
-
首先保存 tmp = cur.next,然后让 cur.next = pre,pre = cur 随后 cur = tmp
-
首先保存 tmp = cur.next,然后让 cur.next = pre,pre = cur 随后 cur = tmp
-
此时 cur == null,所以看图,返回 pre,就是新反转后的链表的头节点。