[leetcode]单链表类题目总结(应用双指针)

来源:互联网 发布:淘宝分销和代销的区别 编辑:程序博客网 时间:2024/06/10 04:15
/** * Definition for singly-linked list. * struct ListNode { *     int val; *     ListNode *next; *     ListNode(int x) : val(x), next(NULL) {} * }; */

24. Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head. 
For example,
Given 1->2->3->4, you should return the list as 2->1->4->3.
Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed

此类对链表顺序作出更改的题目,一般都需要定义一个新节点,以固定该链表。

ListNode* swapPairs(ListNode* head){    if (head == nullptr || head->next == nullptr)        return head;    ListNode anchor(0); anchor.next = head;    ListNode *prev = &anchor, *curr = head, *follow = head->next;    while (follow)    {        curr->next = follow->next;        follow->next = curr;        prev->next = follow;        prev = curr;        curr = curr->next;        if (!curr)            break;        follow = curr->next;    }    return anchor.next;}

Anchor 在这里固定住该链表,使得返回时Anchor->next永远是该链表变换顺序后的头结点。

有没有能不定义多余的结点呢?
可以,使用双指针可以避免定义固定结点。

ListNode* swapPairs(ListNode* head){    ListNode **pp = &head, *curr, *follow;    while ((curr = *pp) && (follow = curr->next))    {        curr->next = follow->next;        follow->next = curr;        *pp = follow;        pp = &(curr->next);    }    return head;}

使用双指针可以让程序更简洁,比如删除单链表中的某一个结点:在这个谈话中,Linus大神就指出使用双指针可以在删除节点的时候不用记录前一节点的信息。
例如要删除第二个结点:

ListNode *head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);head->next->next->next = new ListNode(4);ListNode **pp = &head;pp = &(*pp)->next;*pp = (*pp)->next;

head -> 1 -> 2 -> 3 - > 4
*pp = (*pp)->nextpp中存的是1next指针的地址,该语句直接将该指针存储的结点地址改为2的next指针中的地址,也就是结点3的地址。

206. Reverse Linked List

Reverse a singly linked list. 
Hint:
A linked list can be reversed either iteratively or recursively. Could you implement both?

方法1:定义两个指针p和q,指向相邻的两个结点,使两个结点之间的指向反向,注意要用第三个指针r记录剩下的链表入口。

ListNode* reverseList(ListNode* head) {    if (!head || !(head->next))        return head;    ListNode *p = nullptr, *q = head, *r;    while (q)    {        // store the entry point to the following        r = q->next;        q->next = p;        p = q;        q = r;    }    return head = p;}

方法2:从前往后,将每个结点插到最前面去

  • 1->2->3->4
  • 2->1->3->4
  • 3->2->1->4
  • 4->3->2->1

使用固定结点

// use an anchor nodeListNode* reverseList(ListNode* head) {    if (!head || !(head->next))        return head;    ListNode Anchor(0); Anchor.next = head;    ListNode *prev = head, *curr = head->next;    while (curr)    {        prev->next = curr->next;        curr->next = Anchor.next;        Anchor.next = curr;        curr = prev->next;    }    return Anchor.next;}

使用双指针:

ListNode* reverseList(ListNode* head) {    if (!head) return head;    ListNode **front = &head, **curr = &head->next;    while (*curr)    {        ListNode *tmp1 = *front;        *front = *curr;        ListNode *tmp2 = (*curr)->next;        (*curr)->next = tmp1;        *curr = tmp2;    }    return head;}

其实在上面的循环中,交换的变量只有三个:*front, *curr, (*curr)->next
使用swap函数进一步精简代码:

ListNode* reverseList(ListNode* head){    if (head == nullptr)        return head;    ListNode **front = &head, **curr = &head->next;    for (; *curr; swap(*front, *curr))        swap(*front, (*curr)->next);    return head;}

这道题也可以使用递归处理:

ListNode* reverseList(ListNode* head){    if (head == nullptr || head->next == nullptr)        return head;    auto p = reverseList(head->next);    head->next->next = head;    head->next = nullptr;    return p;}

92. Reverse Linked List II

Reverse a linked list from position m to n. Do it in-place and in one-pass. 
For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,
return 1->4->3->2->5->NULL.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.

ListNode* reverseBetween(ListNode* head, int m, int n){    ListNode **front = &head;    for (int i = 1; i < m; ++i)        front = &(*front)->next;    ListNode *prev = *front;    ListNode *curr = prev->next;    for (int i = 0; i < n - m; ++i)    {        prev->next = curr->next;        curr->next = *front;        *front = curr;        curr = prev->next;    }    return head;}
ListNode* reverseBetween(ListNode *head, int m, int n){    ListNode **a = &head, **b = a;    for (; m--; n--)        a = &(*(b = a))->next;    for (; n--; swap(*b, *a))        swap(*b, (*a)->next);    return head;}

25. Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. 
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5

使用双指针1:

ListNode* reverseKGroup(ListNode* head, int k){    if (k <= 1 || !head || !head->next)        return head;    int length = 0;    for (ListNode *curr = head; curr; curr = curr->next)        ++length;    ListNode **front = &head;    ListNode *prev = head, *curr = nullptr;    while (length >= k)    {        prev = *front;        curr = prev->next;        for (int i = 1; i < k; ++i)        {            prev->next = curr->next;            curr->next = *front;            *front = curr;            curr = prev->next;        }        front = &prev->next;        length -= k;    }    return head;}

使用双指针2:

ListNode* reverseKGroup(ListNode* head, int k){    if (k <= 1 || !head || !head->next)        return head;    int length = 0;    for (ListNode *curr = head; curr; curr = curr->next)        ++length;    ListNode **front = &head;    ListNode **curr;    while (length >= k)    {        curr = &(*front)->next;        for (int i = 1; i < k; ++i)        {            swap((*curr)->next, *front);            swap(*front, *curr);        }        front = curr;        length -= k;    }    return head;}
原创粉丝点击