如何求两个相交链表的第一个相交结点

今天参看《编程之美》之判断链表相交部分,上来就想到了判断最后结点是否相等的方案,亦是该问题的较优方案,遂看了下扩展问题。

1)若有环该咋办?

2)如何求出第一个相交结点?

有环的求解在之前复习链表部分,已经温习过了,在此一笔带过,采用两个指针,分别走1步和2步,若有环,定会相遇(想必相遇大家都会判断)。

那么问题二求解第一个相交结点部分,在《编程之美》里面提到了一个方案二采用hash的方法,由于链表结点的下一个指针都是指向不同的地址,若相同了就是相交部分了。故可采用此方法,分别从两个链表头开始遍历并更新hash表,若无此地址则继续遍历,否则返回第一个相同的地址即可,但此方案的弊端在于需要构建一个Max(Len1, Len2)长度的hash表来存放结点地址。 是否有更优的方案呢?

《编程之美》的该问题的解法三,将链表2的尾部指向2的头,形成一个环,这样如果链表1和2相交,那么我们采用判断环的方法即可知道1和2是否相交了。

接下来我们如何找到环相交的第一个结点呢?

1步指针和2步指针相遇的时候,1步指针应该还没有走遍链表,而2步指针已经在环内走了至少一遍了。

我们可以做如此假设,环的长度为R,1步指针行走了S步与2步指针相遇,那么2S = S + NR (N为环的倍数,不一定是整数倍)

S = NR

我们设 第一个相交结点距离头是A, 第一个相交结点和相遇点距离是X, 此有环链表的长度为L,那么有

A + X = NR (头到相交结点 + 相交结点到相遇结点 即相遇的时候走的长度)

A + X = (N - 1) R + R

A + X = (N - 1) R + L - A (L - A 即为环的长度)

A = (N - 1) R + L - X - A

转N-1环内可省去计算,即 A = L - X - A

此等式意味着,从想遇到继续走到第一个相交焦点的距离等于从头到第一个焦点的距离, Perfect!只要让相遇后的指针继续往后走,同时让一个新指针从头开始走,必然会在到第一个相交结点处相遇,此时该结点正是我们想要的结点。

typedef struct LinkNode {
  int value;
  LinkNode* next;
} LinkNode, *pLinkNode;

// whether has a ring in the list
bool ring(pLinkNode a) {
  pLinkNode i = a->next;
  pLinkNode j = NULL;
  if (!i) 
    return false;

  j = i->next;
  while (i && j && i != j) {
    i = i->next;
    j = j->next->next;
  }
  if (i == j)
    return true;
  return false;
}

pLinkNode find_first_crossed_node(pLinkNode l1) {
  pLinkNode h1 = l1, h2 = l1;

  while (h1 && h2 && h1 != h2) {
    h1 = h1->next;
    h2 = h2->next->next;
  }

  if (!h1 || !h2)
    return NULL;

  pLinkNode h11 = l1;
  while (h11 && h1) {
    h11 = h11->next;
    h1 = h1->next;
    if (h11 == h1)
      break;
  }
  return h11;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值