您的位置:首页 > 其它

“双指针”法解决链表问题

2018-04-02 22:14 309 查看
    背景:单链表问题由于顺序遍历的特性,有时候执行一些操作的时候会出现问题看似需要多次遍历才能获取数据。使用双指针法能在一次遍历中获取更多的数据,也可以节约更多的额外控件。
    “双指针”就是用一个快指针一个慢指针同时进行单链表的顺序扫描。如此就可以使用快指针的时间差给慢指针提供更多的操作信息。下面是两个LeetCode下的习题。
(1)给定一个链表,删除链表的倒数第 n 个节点并返回头结点。
        例如,给定一个链表: 1->2->3->4->5, 并且 n = 2.

当删除了倒数第二个节点后链表变成了 1->2->3->5.
思路:构建先导指针,快于后续指针n-1步,先导指针指向链表尾部时候,慢指针就指向倒数第n个节点 ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* p = head;
ListNode* pe = head;
ListNode* pl = NULL;

for (int i = 0; i < n - 1; ++i){
pe = pe->next;
}
if (pe->next == NULL){
return head->next;
}
pe = pe->next;
p = p->next;
pl = head;

while(pe->next != NULL){
pe = pe->next;
p = p->next;
pl = pl->next;
}
if (p->next){
pl->next = p->next;
}
else{
pl->next = NULL;
}
return head;
}这个答案可以用“dummy node”来优化:增加n-1个先导节点进行优化,这样就不用进行比较繁杂的判空操作,直接告诉向下遍历即可。
(2)给定一个链表,判断链表中否有环。
传统思路:找个容器把出现的点存起来,出现重复点就判断成环(缺点很明显:额外内存占用)bool hasCycle(ListNode *head) {
std::set<ListNode*> sl;
if (!head){
return false;
}
while(head->next){
if (sl.find(head) != sl.end()){
return true;
}
else{
sl.insert(head);
head = head->next;
}
}
return false;
}双指针思路:快指针比慢指针先走,如果快指针被慢指针追上,说明进入闭环ListNode* fastNode = head;
ListNode* slowNode = head;

if (head == nullptr)
{
return false;
}

while (fastNode && fastNode->next)
{
slowNode = slowNode->next;
fastNode = fastNode->next->next;

if (slowNode == fastNode)
{
return true;
}
}总结:用双指针能够靠速度差或者位置差更加方便的处理定位和列表结构的信息,从而构造出更低复杂度的算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单链表 双指针