• 剑指offer-链表相关


    剑指offer面试常考手撸算法题-链表篇

    1. 从头到尾打印链表

     1 class Solution {
     2 public:
     3     // 可以先压栈,再出栈到vector
     4     // 时间/空间:O(n)
     5     vector<int> printListFromTailToHead(ListNode* head) {
     6         if(head == nullptr)
     7             return {};
     8         vector<int> res;
     9         stack<int> s;
    10         while(head != nullptr)
    11         {
    12             s.push(head->val);
    13             head = head->next;
    14         }
    15         while(!s.empty())
    16         {
    17             res.push_back(s.top());
    18             s.pop();
    19         }
    20         return res;
    21     }
    22     // 可以直接插入vector中,翻转vector
    23     // 时间/空间:O(n)
    24     vector<int> printListFromTailToHead(ListNode* head) {
    25         vector<int> res;
    26         if(head == nullptr)
    27             return {};
    28         while(head)
    29         {
    30             res.push_back(head->val);
    31             head = head->next;
    32         }
    33         reverse(res.begin(), res.end());
    34         return res;
    35     }
    36 };

    2. 链表中倒数第k个节点

     1 class Solution {
     2 public:
     3     //快慢指针,快指针先走k-1步,之后一起走,直到快指针到达链表尾。
     4     //时间:O(n), 空间O(1)
     5     ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
     6         if(pListHead == nullptr || k == 0)
     7             return nullptr;
     8         auto p = pListHead;
     9         for(int i=0; i<k-1; i++)
    10         {
    11             if(p->next == nullptr)
    12                 return nullptr;
    13             p = p->next;
    14         }
    15         while(p->next != nullptr)
    16         {
    17             p = p->next;
    18             pListHead = pListHead->next;
    19         }
    20         return pListHead;
    21     }
    22 };

    3. 翻转链表

     1 class Solution {
     2 public:
     3     //一个取巧的方法(如果允许使用额外空间):先遍历链表用栈存储元素值,然后重新遍历链表,将链表值置为栈顶。
     4     //时间:O(n), 空间O(n)
     5     ListNode* ReverseList(ListNode* pHead) {
     6         stack<int> s;
     7         auto p = pHead, q = pHead;
     8         while(pHead != nullptr)
     9         {
    10             s.push(pHead->val);
    11             pHead = pHead->next;
    12         }
    13         while(p != nullptr)
    14         {
    15             p->val = s.top();
    16             s.pop();
    17             p = p->next;
    18         }
    19         return q;
    20     }
    21 };
     1 class Solution {
     2 public:
     3     //2. 真正地翻转链表,交换地址
     4     ListNode* ReverseList(ListNode* pHead) {
     5         if(pHead == nullptr)
     6             return nullptr;
     7         decltype(pHead) pre = nullptr;
     8         auto next = pre;
     9         ListNode *res = nullptr;
    10         while(pHead != nullptr)
    11         {
    12             next = pHead->next;
    13             if(next == nullptr)
    14                 res = pHead;
    15             pHead->next = pre;
    16             pre = pHead;
    17             pHead = next;
    18         }
    19         return res;
    20     }
    21 };

    4. 合并两个排序链表

     1 class Solution {
     2 public:
     3     //非递归版本:双指针分别遍历两个链表
     4     ListNode* Merge1(ListNode* pHead1, ListNode* pHead2)
     5     {
     6         if(pHead1 == nullptr)
     7             return pHead2;
     8         if(pHead2 == nullptr)
     9             return pHead1;
    10         ListNode *head = new ListNode(0);
    11         head->next = nullptr;
    12         ListNode *res = head;
    13         while(pHead1 != nullptr && pHead2 != nullptr)
    14         {
    15             if(pHead1->val <= pHead2->val)
    16             {
    17                 head->next = pHead1;
    18                 head = head->next;
    19                 pHead1 = pHead1->next;
    20             }
    21             else
    22             {
    23                 head->next = pHead2;
    24                 head = head->next;
    25                 pHead2 = pHead2->next;
    26             }
    27         }
    28         if(pHead1 != nullptr)
    29             head->next = pHead1;
    30         else
    31             head->next = pHead2;
    32         return res->next;
    33     }
    34     //递归版本
    35     ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    36     {
    37         if(pHead1 == nullptr)
    38             return pHead2;
    39         if(pHead2 == nullptr)
    40             return pHead1;
    41         
    42         ListNode* head = nullptr;
    43         if(pHead1->val <= pHead2->val)
    44         {
    45             head = pHead1;
    46             head->next = Merge(pHead1->next, pHead2);
    47         }
    48         else
    49         {
    50             head = pHead2;
    51             head->next = Merge(pHead2->next, pHead1);
    52         }
    53         return head;
    54     }
    55 };

    5. 两个链表第一个公共节点

     9 class Solution {
    10 public:
    11     //暴力法太低级,O(n2)不可接受
    12     //使用unordered_map存储一个链表节点吧,时间O(n),空间O(n)
    13     //unordered_map使用[]/insert插入,不是push_back()
    14     ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
    15         if(pHead1 == nullptr)
    16             return nullptr;
    17         if(pHead2 == nullptr)
    18             return nullptr;
    19         
    20         unordered_map<int, ListNode*> ump;
    21         while(pHead1 != nullptr)
    22         {
    23             ump.insert({pHead1->val, pHead1});
    24             pHead1 = pHead1->next;
    25         }
    26         while(pHead2 != nullptr)
    27         {
    28             auto res = ump.find(pHead2->val);
    29             if(res != ump.end())
    30                 return res->second;
    31             pHead2 = pHead2->next;
    32         }
    33         return nullptr;
    34     }
    35 };

    6. 链表中环的入口节点(快2满1指针判断成环,再走一圈计算环长,快慢指针找到入口)

    判断链表是否成环(快慢指针解决)

     1 /*
     2 struct ListNode {
     3     int val;
     4     struct ListNode *next;
     5     ListNode(int x) :
     6         val(x), next(NULL) {
     7     }
     8 };
     9 */
    10 class Solution {
    11 public:
    12     //判断成环及入口:快慢指针
    13     ListNode* EntryNodeOfLoop(ListNode* pHead)
    14     {
    15         if(pHead == nullptr)
    16             return nullptr;
    17         ListNode *pMeet = judgeLoop(pHead);
    18         if(pMeet == nullptr)//未成环
    19             return nullptr;
    20         auto p = pMeet;
    21         int loopLen = 1;
    22         //计算环长,相遇点再走一圈
    23         while(p->next != pMeet)
    24         {
    25             p = p->next;
    26             loopLen++;
    27         }
    28         auto q = pHead;
    29         //后指针先走环长
    30         while(loopLen--)
    31         {
    32             q = q->next;
    33         }
    34         //快慢一起走
    35         p = pHead;
    36         while(p != q)
    37         {
    38             p = p->next;
    39             q = q->next;
    40         }
    41         return p;
    42     }
    43     //判断是否成环,快指针走两步-慢指针走一步,指针相遇必在环内
    44     ListNode* judgeLoop(ListNode* pHead)
    45     {
    46         if(pHead == nullptr)
    47             return nullptr;
    48         auto pSlow = pHead->next;
    49         if(pSlow == nullptr)
    50             return nullptr;
    51         auto pFast = pSlow->next;
    52         while(pSlow != nullptr && pFast != nullptr)
    53         {
    54             if(pSlow == pFast)
    55                 return pSlow;
    56             pSlow = pSlow->next;
    57             pFast = pFast->next;
    58             if(pFast != nullptr)
    59                 pFast = pFast->next;
    60         }
    61         return nullptr;
    62     }
    63 };

    7. 删除链表重复节点(重复保留一个)

     1 class Solution {
     2 public:
     3     //一次遍历,前后节点值相等,删除后一节点
     4     ListNode* deleteDuplication(ListNode* pHead)
     5     {
     6         if(pHead == nullptr)
     7             return nullptr;
     8         auto pre = pHead;
     9         auto cur = pre->next;
    10         while(cur != nullptr)
    11         {
    12             while(cur->val == pre->val)
    13             {
    14                 pre->next = cur->next;
    15                 cur = pre->next;
    16                 if(cur == nullptr)
    17                     return pHead;
    18             }
    19             pre = cur;
    20             cur = cur->next;
    21         }
    22         return pHead;
    23     }
    24 };

    8. 删除链表重复节点(重复节点不保留)

     1 class Solution {
     2 public:
     3     /*创建一个头节点,它的next指向链表头,然后再用两个指针
     4     一前一后来遍历链表,后一个指针判断有无重复并进行后移*/
     5     ListNode* deleteDuplication(ListNode* pHead)
     6     {
     7         if(pHead == nullptr)
     8             return nullptr;
     9         ListNode *first = new ListNode(0);
    10         first->next = pHead;
    11         ListNode *last = first;
    12         ListNode *p = pHead;
    13         while(p != nullptr && p->next != nullptr)
    14         {
    15             if(p->val == p->next->val)//有重复,需要删除
    16             {
    17                 int val = p->val;
    18                 while(p != nullptr && p->val == val)
    19                     p = p->next;
    20                 last->next = p;
    21             }
    22             else
    23             {
    24                 last = p;
    25                 p = p->next;
    26             }
    27         }
    28         return first->next;
    29     }
    30 };

    9. 判断两个链表是否交叉

    (同样可使用一个unordered_map来存储一个链表中的节点指针,再遍历另外一个链表逐个查找)

     1 bool FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
     2     if(pHead1 == nullptr || pHead2 == nullptr)
     3         return false;
     4     unordered_map<ListNode*, int> ump;
     5     while(pHead1 != nullptr)
     6     {
     7         ump.insert({pHead1, pHead1->val});
     8         pHead1 = pHead1->next;
     9     }
    10     while(pHead2 != nullptr)
    11     {
    12         auto res = ump.find(pHead2);
    13         if(res != ump.end())
    14             return true;
    15         pHead2 = pHead2->next;
    16     }
    17     return false;
    18 }

    10.相交链表

    O(n)

     1 class Solution {
     2 public:
     3     ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
     4         auto p = headA, q = headB;
     5         while(p != q)
     6         {
     7             if(p == q)
     8                 return p;
     9             p = (p == nullptr) ? headB : p->next;
    10             q = (q == nullptr) ? headA : q->next;
    11         }
    12         return p;
    13     }
    14 };

    说明:以上其他题目代码由牛客oj/leetcode通过,第9个未测试。

    11.删除链表第n个节点(leetcode 19)

    O(n)

     1 class Solution {
     2 public:
     3     ListNode* removeNthFromEnd(ListNode* head, int n) {
     4         int len = 0;
     5         auto p = head;
     6         while(p != nullptr)//计算表长
     7         {
     8             len++;
     9             p = p->next;
    10         }
    11         if(n > len)//边界处理
    12             return nullptr;
    13         
    14         len = len-n-1;//先走len-n-1步
    15         p = head;
    16         if(len < 0)//删除头节点
    17             return p->next;
    18         
    19         while(len--)//删除其他节点
    20             p = p->next;
    21         p->next = p->next->next;
    22         return head;
    23     }
    24 };

    the end.

  • 相关阅读:
    BSOJ 4490 避难向导
    【水题】求条件最大值
    【模拟】神奇的树
    【模拟】2014ACM/ICPC亚洲区北京站-A-(Curious Matt)
    【模拟】refresh的停车场
    数据结构实验之栈三:后缀式求值 (stack)
    【STL】Message Flood(set)
    【STL】完美网络(优先队列实现)
    【搜索BFS】走迷宫(bfs)
    【STL】deque双向队列(转载)
  • 原文地址:https://www.cnblogs.com/yocichen/p/11333367.html
Copyright © 2020-2023  润新知