链表的基本解题办法

一.快慢指针
快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
他主要用于下面三种情景:
1.判断链表中是否有环
题目内容
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

思路:这道题用快慢指针可以很快的做出来。那到底什么是快慢指针呢?
快慢指针
先说结论:在有环的链表里,快慢指针同时从头指针出发,最终一定会相遇。
为啥他们最终会相遇呢:首先快指针速度一般为慢指针的两倍
即慢指针slow=head->next;快指针fast=head->next->next;
如果一个链表当中有环的话,他们最终会在环中循环,而他们的相对速度为1,变换参考系,可以看做slow不动,而fast的速度为1,在环中最终会相遇。

代码:
bool hasCycle(struct ListNode *head)
{
if(headNULL) return false;
struct ListNode *slow=head;
struct ListNode *fast=head;
while(slow&&fast&&fast->next)//画个图,要让链表里的节点都不为NULL
{
slow=slow->next;
fast=fast->next->next;
if(slow
fast) return true;//在环中最终会相遇
}
return false;//从循环能退出就说明不是环
}
2.寻找链表当中最中间的值
给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

示例 1:
输入:[1,2,3,4,5]输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

代码:
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
}
return slow;

}

3.返回倒数第 k 个节点

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
注意:本题相对原题稍作改动
示例:
输入: 1->2->3->4->5 和 k = 2
输出: 4
思路:链表只能从头往后遍历,要找到倒数第k个数,只需要弄个快慢指针,让快指针先走K步,然后让快慢指针同时走,直到快指针走到结束。这时慢指针正指向倒数第K个节点。

代码:public int kthToLast(ListNode head, int k) {
ListNode slow=head,fast=head;
while(true){
k–;
if(k==0) break;
fast = fast.next;
}
while(fast.next!=null){
fast =fast.next;
slow = slow.next;
}
return slow.val;

}

二.设置头结点的小技巧
移除链表元素
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
思路:设置一个头结点便于操作。
代码:
public ListNode removeElements(ListNode head, int val) {
ListNode pre = new ListNode(-1);
pre.next = head;
ListNode p = pre;
while(p.next!=null){
if(p.next.val==val){
p.next = p.next.next;
}
else{
p = p.next;
}
}
return pre.next;

}

三.反转链表
定义一个函数,输入一个链表的头节点,反转该链表
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
1.迭代法
代码:
public ListNode reverseList(ListNode head) {
ListNode pre = null, cur = head, next = null;
while(cur!=null){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}

2.递归法
class Solution {
public ListNode reverseList(ListNode head) {
if(headnull || head.nextnull) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}

四.快慢指针和反转链表的综合应用
回文链表
编写一个函数,检查输入的链表是否是回文的。
示例 1:
输入: 1->2输出: false
示例 2:
输入: 1->2->2->1输出: true
思路:先用快慢指针找到链表的中间结点,然后反转后半段链表,从两头遍历对比。
代码:
public boolean isPalindrome(ListNode head) {
if(head==null) return true;
ListNode slow=head,fast=head;
while(fast!=null&&fast.next!=null){
fast = fast.next.next;
slow = slow.next;
}
ListNode pre = null,next = null;
while(slow!=null){
next = slow.next;
slow.next = pre;
pre = slow;
slow = next;
}
while(pre!=null){
if(head.val!=pre.val){
return false;
}
pre=pre.next;
head=head.next;
}
return true;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值