刷题有术--“链表” 必备技巧

在面试中,链表经常作为简单题出现,虽然题目不难,但是面试者常常会因疏忽实现细节,造成无法短时间内bug-free。

今天小编总结链表常用知识点。点赞收藏,关注公众号[眼罩的程序员笔记],面试前看一遍,快速通关链表题型。

基础操作

01. 快慢指针找中间节点

无论当链表中有奇数还是偶数个节点,slow fast 两指针一开始都指向head。慢指针一次走一步,快指针一次走两步。 直至fast 为NULL或者fast->next为NULL时,此时slow 指向中间节点。

循环结束后指针状态见下图。

ListNode * findMiddle(ListNode * head)
{
   ListNode * slow = head;
   ListNode * fast = head;
   while(fast!=NULL && fast->next!=NULL)
   {
      slow = slow->next;
      fast = fast->next->next;
   }
   return slow;
}

02. 原地翻转

不断向后移动相邻的两个指针,翻转两指针间的相邻关系,需注意在翻转之前保存后一个指针的next节点。并且最后把原head的next置为NULL。

如下图红色代表循环第一步,蓝色代表循环第二步。

ListNode * reverse(ListNode * head)
 {
    if (head==NULL)
      return NULL;
    ListNode * i = head;
    ListNode * j = head->next;
    while(j!=NULL)
    {
       ListNode * tem = j->next;
       j->next = i;
       i= j;
       j=tem;
    }
    head->next = NULL;
    return i;
 }

03. 合并链表

给定两个链表,要求依次选取其中一个节点,合并两个链表。

下图是一个通用的合并思路,这个思路不仅适用于依次选取节点合并,还适用于将两个有序链表合并为一个有序链表。

首先建立一个dummy 头节点作为合并后链表的dummy头结点,用一个尾指针指向合并后链表的最后一个节点。每次循环将tail 连接到headA,headA 连接到 headB,之后tail 更新为headB。

下图中红线代表循环第一轮,蓝线代表循环第二轮。

ListNode * merge(ListNode * a, ListNode * b)
{
   ListNode * dummy = new ListNode(-1);
   ListNode * pre = dummy;
   while(a!=NULL && b!=NULL)
   {
      pre->next = a;
      ListNode * aTem = a->next;
      a->next = b;
      pre=b;
      b=b->next;
      a=aTem;
   }
   if(a!=NULL)
   {
      pre->next= a;
   }
   else if (b!=NULL)
   {
      pre->next =b;
   }
   return dummy->next;
}

链表排序

题目:给定链表的头结点 head ,请将其按升序排列并返回 排序后的链表 。

链表的特点造成无法方便的交换任意两个任意位置的节点,所以无法使用快排类的排序算法。

而归并排序非常适合链表排序。递归从底到上,相当将长度为1 的子链表排序之后两个合并成长度2的链表;依次递推。

实现过程就用到了上述基础操作中的「快慢指针找中间节点」来把链表一分为二;用「合并链表」将排序好的子链表合并成一个有序的长链表。

链表有环

1. 给你一个链表的头节点 head ,判断链表中是否有环?

这个题比较简单就是使用快慢指针,慢指针一次走一步,快指针一次走两步,如果快指针在走到结尾之前和慢指针相遇了说明有环,如果没相遇则无环。

2. 如果链表有环,则返回环的起点。

这是上题的follow up, 先明确符号含义:

x: 头结点到 entry红点之间的长度;

y: entry 红点到 meet 红点之间的长度;

m:meet红点 到 entry 红点之间的长度;

R:环的整个长度;

t:  t时刻快慢指针在meet点相遇。

假设快慢指针在环内的meet点相遇。

快指针走的距离是慢指针走的距离的两倍,有如下两个等式:

2t = x + n* R + y(快指针);

  t  = x + y         (慢指针)

通过这两个等式可以得到 x = n*R - y;   推出 x = m + (n-1)*R。说明相遇之后将慢指针重新放回起点,快指针后面一次只走一步,两个指针再次相遇的点即为entry 入口点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值