题目
分隔链表
题目描述:
给你一个链表,再给你一个target,保证:所有小于target的节点都在大于等于target节点的前面
解题思路:
其实题目的意思就是:让你分别表示大于等于target的链表和小于target的链表,然后让两个链表结合起来,就可以完成。
思路很简单,写起来也很轻松,但是,可能你第一遍的时候做不对🙄(因为我做错了),原因其实很简单,就是因为p.next后面比较混乱,画个图举个例子
其实我们只需要两个链表,也就是有一些黑色的线,我们不需要,这时候我们就需要断开线子
那么我们怎么才算是断开线呢?
p.next = null;
代码:
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function partition(head: ListNode | null, x: number): ListNode | null {
// 其实这题,也就是将一个链表分割为两个链表
let dummy1 = new ListNode(-1);
let dummy2 = new ListNode(-1);
let small = dummy1;
let large = dummy2;
let p = head;
while(p!== null){
if(p.val >= x){
large.next = p;
// large向前进一位
large = large.next
}else{
small.next = p;
// small向前进一位
small = small.next;
}
// p = p.next;
// 断开原链表里面的next指针
// 如果不断开连接,最终可能不是两个链表,就会出现指向混乱
let temp = p.next;
// 让p的指针消失,其实就是避免产生三个柔和的链表的感觉
p.next = null;
p = temp;
}
// 现在将两个重合起来
small.next = dummy2.next;
return dummy1.next
};
反转链表
题目描述:
大概意思就是,给你一个链表的头节点,请你将链表反转过来
思路:
这边应该是很容易想到使用pre和cur两个指针,只要我不断地将他们的next指向反过来,那么我不是就可以实现了嘛
代码
function reverseList(head: ListNode | null): ListNode | null {
// 将链表进行反转
// 设置pre节点,next节点,和cur节点
let pre = null
let cur = head
while(cur!== null){
// 为了一直向后进行
let nxt = cur.next
cur.next = pre;
pre = cur
cur = nxt
}
return pre
};
这边我们其实最主要的就是cur.next= pre,这就是将那个箭头扳过来,但是为什么我们需要其他的那三条语句呢?
因为我们需要继续向后面去反转啊,那么我们就需要让pre去占领cur的位置,让cur去占领nxt的位置,这样就可以一直反转到最后
移除链表元素
题目描述:
给你一个链表的头节点,并且给你一个target,希望你将链表里,所有等于target的值全部去掉
思路:
我们可以直接进行遍历,然后去寻找那个target值,当找到了,我们就直接跳过他
代码:
function removeElements(head: ListNode | null, val: number): ListNode | null {
let dummy = new ListNode(0,head);
let data = dummy;
while(data.next && data){
if(data.next.val === val){
//那么需要跳过这个节点
// nextdata = nextdata.next
data.next = data.next.next
continue
}
data = data.next
}
return dummy.next
};
链表中的倒数第K个节点
链接:剑指 Offer 22. 链表中倒数第k个节点 - 力扣(LeetCode)
思路:
-
其实对于暴力解,我们应该都能想到
- 倒数第K个节点,那么对于链表,我们希望得到正着数的第
n-k个节点,那就意味着,我们需要知道,这个链表需要多少个节点,然后我们去找到第n-k+1个(题目说,是从下标一开始) - 也就是说,这么做,其实我们需要两个
for循环,那么想想怎么使用一个for循环呢?
- 倒数第K个节点,那么对于链表,我们希望得到正着数的第
-
东哥提供了一种思路,非常巧妙
- 这样我们就可以不用求链表的长度,用两个指针,用相对位置求出倒数第k个节点
代码:
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function getKthFromEnd(head: ListNode | null, k: number): ListNode | null {
// 思路:
// 首先找到第K个节点
let p1 = head;
let index = 0;
while(index < k){
p1 = p1.next;
index++
}
let p2 = head;
// 现在利用相对距离
while(p1 !== null){
p2 = p2.next;
p1 = p1.next
}
return p2
};
参考链接:双指针技巧秒杀七道链表题目 :: labuladong的算法小抄 (gitee.io)
总结
今天看的这几道题,其实都不是很难,但是需要注意一些细节,并且需要巧妙地使用工具节点
第一题:我们需要避免产生指针指向混乱的情况,所以,需要将原链表的next指针
第二题:我们需要使用两个指针,然后再遍历的过程中,将他们的位置改变
第四题:双指针,但是用相对位置来求出答案,非常巧妙。
工具节点:我的理解就是,当你想对链表增删改查的时候,后面有需要输出链表啥的,你就可以设置dummyNode,感觉它就像一个工具节点一样。
额,我理解的工具节点就是那种:值和头节点值一样的那个节点(自己认为设置的)
let p1 = head;//p1,我就认为是工具节点