• 链表常见题目总结


    1.从尾到头打印链表

    题目描述:

    输入一个链表,返回一个反序的链表

    实现代码:

    class Solution {
    public:
        vector<int> printListFromTailToHead(ListNode* head) {
            stack<int> nodes;
            vector<int> result;
            ListNode* node = head;
            while(node != NULL){
                nodes.push(node->val);
                node = node->next;
            }
            
            while(!nodes.empty()){
                result.push_back(nodes.top());
                nodes.pop();
            }
            return result;
        }
    };

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

    题目描述:
    输入一个链表,输出该链表中倒数第k个结点。
    实现代码:
    class Solution {
    public:
        ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
            if(pListHead == NULL || k == 0){
                return NULL;
            }
            ListNode *pAhead = pListHead;
            ListNode *pBehind = pListHead;
            for(unsigned int i = 0; i < k - 1; i++){
                if(pAhead->next != NULL){
                    pAhead = pAhead->next;
                }
                else{
                    return NULL;
                }
            }
            while(pAhead->next != NULL){
                pAhead = pAhead->next;
                pBehind = pBehind->next;
            }
            return pBehind;
        }
    };

    3.反转链表

    题目描述:
    输入一个链表,反转链表后,输出链表的所有元素。
    实现代码:
    class Solution {
    public:
        ListNode* ReverseList(ListNode* pHead) {
            ListNode* pReversedHead = NULL;
            ListNode* pNode = pHead;
            ListNode* pPrev = NULL;
            while(pNode != NULL){
                ListNode* pNext = pNode->next;
                if(pNext == NULL){
                    pReversedHead = pNode;
                }
                pNode->next = pPrev;
                pPrev = pNode;
                pNode = pNext;
            }
            return pReversedHead;
        }
    };

    4.合并两个排序链表

    题目描述:
    输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
    实现代码:
    class Solution {
    public:
        ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
        {
            //判断指针是否为空
            if(pHead1 == NULL){
                return pHead2;
            }
            else if(pHead2 == NULL){
                return pHead1;
            }
            ListNode* pMergedHead = NULL;
            if(pHead1->val < pHead2->val){
                pMergedHead = pHead1;
                   pMergedHead->next = Merge(pHead1->next, pHead2);
            }
            else{
                pMergedHead = pHead2;
                   pMergedHead->next = Merge(pHead1, pHead2->next);
            }
            return pMergedHead;
        }
    };

    5.复杂链表的复制

    题目描述:
    输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
    实现代码:
    class Solution {
    public:
        
        //第一步,复制复杂指针的label和next
        void CloneNodes(RandomListNode* pHead){
            RandomListNode* pNode = pHead;
            while(pNode != NULL){
                RandomListNode* pCloned = new RandomListNode(0);
                pCloned->label = pNode->label;
                pCloned->next = pNode->next;
                pCloned->random = NULL;
                
                pNode->next = pCloned;
                pNode = pCloned->next;
            }
        }
        
        //第二步,处理复杂指针的random
        void ConnectSiblingNodes(RandomListNode* pHead){
            RandomListNode* pNode = pHead;
            while(pNode != NULL){
                RandomListNode* pCloned = pNode->next;
                if(pNode->random != NULL){
                    pCloned->random = pNode->random->next;
                }
                pNode = pCloned->next;
            }
        }
        
        //第三步,拆分复杂指针
        RandomListNode* ReconnectNodes(RandomListNode* pHead){
            RandomListNode* pNode = pHead;
            RandomListNode* pClonedHead = NULL;
            RandomListNode* pClonedNode = NULL;
            
            if(pNode != NULL){
                pClonedHead = pClonedNode = pNode->next;
                pNode->next = pClonedNode->next;
                pNode = pNode->next;
            }
            
            while(pNode != NULL){
                pClonedNode->next = pNode->next;
                pClonedNode = pClonedNode->next;
                pNode->next = pClonedNode->next;
                pNode = pNode->next;
            }
            return pClonedHead;
        }
        
        RandomListNode* Clone(RandomListNode* pHead)
        {
            CloneNodes(pHead);
            ConnectSiblingNodes(pHead);
            return ReconnectNodes(pHead);
        }
    };

    6.两个链表的第一个公共节点

    问题描述:
    输入两个链表,找出它们的第一个公共结点。
    实现代码:
    class Solution {
    public:
        ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
            // 如果有一个链表为空,则返回结果为空
            if(pHead1 == NULL || pHead2 == NULL){
                return NULL;
            }
            // 获得两个链表的长度
            unsigned int len1 = GetListLength(pHead1);
            unsigned int len2 = GetListLength(pHead2);
            // 默认 pHead1 长, pHead2短,如果不是,再更改
            ListNode* pHeadLong = pHead1;
            ListNode* pHeadShort = pHead2;
            int LengthDif = len1 - len2;
            // 如果 pHead1 比 pHead2 小
            if(len1 < len2){
                ListNode* pHeadLong = pHead2;
                ListNode* pHeadShort = pHead1;
                int LengthDif = len2 - len1;
            }
            // 将长链表的前面部分去掉,使两个链表等长
            for(int i = 0; i < LengthDif; i++){
                pHeadLong = pHeadLong->next;
            }
            
            while(pHeadLong != NULL && pHeadShort != NULL && pHeadLong != pHeadShort){
                pHeadLong = pHeadLong->next;
                pHeadShort = pHeadShort->next;
            }
            return pHeadLong;
        }
    private:
        // 获得链表长度
        unsigned int GetListLength(ListNode* pHead){
            if(pHead == NULL){
                return 0;
            }
            unsigned int length = 1;
            while(pHead->next != NULL){
                pHead = pHead->next;
                length++;
            }
            return length;
        }
    };

    7.链表中环的入口节点

    题目描述:
    一个链表中包含环,请找出该链表的环的入口结点。
    实现代码:
    class Solution {
    public:
        ListNode* EntryNodeOfLoop(ListNode* pHead)
        {
            if(pHead == NULL){
                return NULL;
            }
            ListNode* meetingnode = MeetingNode(pHead);
            if(meetingnode == NULL){
                return NULL;
            }
            // 回环链表结点个数
            int nodesloop = 1;
            // 找到环中结点个数
            ListNode* pNode1 = meetingnode;
            while(pNode1->next != meetingnode){
                pNode1 = pNode1->next;
                nodesloop++;
            }
            pNode1 = pHead;
            // 第一个指针向前移动nodesloop步
            for(int i = 0; i < nodesloop; i++){
                pNode1 = pNode1->next;
            }
            // 两个指针同时移动,找到环入口
            ListNode* pNode2 = pHead;
            while(pNode1 != pNode2){
                pNode1 = pNode1->next;
                pNode2 = pNode2->next;
            }
            return pNode1;
        }
    private:
        // 使用快慢指针,找到任意的一个环中结点
        ListNode* MeetingNode(ListNode* pHead){
            ListNode* pSlow = pHead->next;
            if(pSlow == NULL){
                return NULL;
            }
            ListNode* pFast = pSlow->next;
            while(pFast != NULL && pSlow != NULL){
                if(pFast == pSlow){
                    return pFast;
                }
                pSlow = pSlow->next;
                pFast = pFast->next;
                if(pFast != NULL){
                    pFast = pFast->next;
                }
            }
            return NULL;
        }
    };

    8.删除链表中重复节点

    题目描述:
    在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5。
    实现代码:
    class Solution {
    public:
        ListNode* deleteDuplication(ListNode* pHead)
        {
            if(pHead == NULL){
                return NULL;
            }
            // 指向当前结点前最晚访问过的不重复结点
            ListNode* pPre = NULL;
            // 指向当前处理的结点
            ListNode* pCur = pHead;
            // 指向当前结点后面的结点
            ListNode* pNext = NULL;
            
            while(pCur != NULL){
                // 如果当前结点与下一个结点相同
                if(pCur->next != NULL && pCur->val == pCur->next->val){
                    pNext = pCur->next;
                    // 找到不重复的最后一个结点位置
                    while(pNext->next != NULL && pNext->next->val == pCur->val){
                        pNext = pNext->next;
                    }
                    // 如果pCur指向链表中第一个元素,pCur -> ... -> pNext ->...
                    // 要删除pCur到pNext, 将指向链表第一个元素的指针pHead指向pNext->next。
                    if(pCur == pHead){
                        pHead = pNext->next;
                    }
                    // 如果pCur不指向链表中第一个元素,pPre -> pCur ->...->pNext ->...
                    // 要删除pCur到pNext,即pPre->next = pNext->next
                    else{
                        pPre->next = pNext->next;
                    }
                    // 向前移动
                    pCur = pNext->next;
                }
                // 如果当前结点与下一个结点不相同
                else{
                    pPre = pCur;
                    pCur = pCur->next;
                }
            }
            return pHead;
        }
    };

    9.两数相加

    题目描述:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

    您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

    示例:

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807

    实现代码:
    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            ListNode *result = new ListNode(0);
            ListNode *temp = result;
            int sum = 0;
            while(l1||l2)
            {
                if(l1)
                {
                    sum = sum + l1->val;
                    l1 = l1->next;
                }
                if(l2)
                {
                    sum = sum + l2->val;
                    l2 = l2->next;
                }
                temp -> next = new ListNode(sum % 10);
                sum = sum/10;
                temp = temp->next;
            }
            if (sum)
                temp->next = new ListNode(1);
            return result->next;
            
            
        }
    };

    10.删除链表的倒数第N个节点

    题目描述:
    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

    示例:

    给定一个链表: 1->2->3->4->5, 和 n = 2.

    当删除了倒数第二个节点后,链表变为 1->2->3->5.

    说明:

    给定的 n 保证是有效的。

    进阶:

    你能尝试使用一趟扫描实现吗?

    实现代码:
    class Solution {
    public:
        ListNode* removeNthFromEnd(ListNode* head, int n) {
            ListNode *pre = new ListNode(0);
            pre->next = head;
            ListNode *p = pre;
            ListNode *q = pre;
            for(int i = 0; i < n; i++)
            {
                p = p->next;
            }
            while(p->next != NULL)
            {
                p = p->next;
                q = q->next;
            }
            ListNode *k = q->next;
            if(k == head)
            {
                head = head->next;
                delete k;
                return head;
            }
            q->next = k->next;
            delete k;
            return head;
        }
    };

    11.合并k个有序链表

    题目描述:
    合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

    示例:

    输入:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    输出: 1->1->2->3->4->4->5->6
    实现代码:
    class Solution {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            if (lists.empty()) return NULL;
            int n = lists.size();
            while (n > 1) {
                int k = (n + 1) / 2;
                for (int i = 0; i < n / 2; ++i) {
                    lists[i] = mergeTwoLists(lists[i], lists[i + k]);
                }
                n = k;
            }
            return lists[0];
        }
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
            ListNode *dummy = new ListNode(-1), *cur = dummy;
            while (l1 && l2) {
                if (l1->val < l2->val) {
                    cur->next = l1;
                    l1 = l1->next;
                } else {
                    cur->next = l2;
                    l2 = l2->next;
                }
                cur = cur->next;
            }
            if (l1) cur->next = l1;
            if (l2) cur->next = l2;
            return dummy->next;
        }
    };

    12.两两交换链表中的节点

    题目描述:
    给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

    你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

     

    示例:

    给定 1->2->3->4, 你应该返回 2->1->4->3.

    实现代码:
    class Solution {
    public:
        ListNode* swapPairs(ListNode* head) {
            if(!head||!head->next) return head;//空链和一个元素的链直接返回
            ListNode* l=head;//定义需要交换的左右节点
            ListNode* r=l->next;
            ListNode* p;
            l->next=r->next;//交换第一二个节点
            r->next=l;
            head=r;//首节点赋值为第二个节点
            p=l;//p赋值为第一对交换成功的右节点
            while(l->next&&l->next->next){//如果剩余节点为0或1则返回head,否则进入循环
                l=l->next;//转换到下一节点对
                r=l->next;
                l->next=r->next;//交换节点l,r
                r->next=l;
                p->next=r;
                p=l;
            }
            return head;  
            }
            
    };

    13.旋转链表

    题目描述:
    给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

    示例 1:

    输入: 1->2->3->4->5->NULL, k = 2
    输出: 4->5->1->2->3->NULL
    解释:
    向右旋转 1 步: 5->1->2->3->4->NULL
    向右旋转 2 步: 4->5->1->2->3->NULL

    示例 2:

    输入: 0->1->2->NULL, k = 4
    输出: 2->0->1->NULL
    解释:
    向右旋转 1 步: 2->0->1->NULL
    向右旋转 2 步: 1->2->0->NULL
    向右旋转 3 步: 0->1->2->NULL
    向右旋转 4 步: 2->0->1->NULL

    实现代码:
    class Solution {
    public:
        ListNode* rotateRight(ListNode* head, int k) {
              if (!head) return NULL;
              int n = 0;
              ListNode *cur = head;
              while (cur) {
                  ++n;
                  cur = cur->next;
             }
             k %= n;
             ListNode *fast = head, *slow = head;
             for (int i = 0; i < k; ++i) {
                 if (fast) fast = fast->next;
             }
             if (!fast) return head;
             while (fast->next) {
                 fast = fast->next;
                 slow = slow->next;
             }
             fast->next = head;
             fast = slow->next;
             slow->next = NULL;
             return fast;
        }
    };

    14.输出链表中的重复元素

    题目描述:
    给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

    示例 1:

    输入: 1->1->2
    输出: 1->2

    示例 2:

    输入: 1->1->2->3->3
    输出: 1->2->3
    实现代码:
    class Solution {
    public:
        ListNode* deleteDuplicates(ListNode* head) {
            ListNode* cur = head;
            while(cur != NULL){
                ListNode* rear = cur->next;
                if(rear == NULL)
                    return head;
                if(cur->val == rear->val)
                    cur->next = rear->next;
                else
                    cur = cur->next;
            }
            return head;
        }
    };

    15.分隔链表

    题目描述:
    给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

    你应当保留两个分区中每个节点的初始相对位置。

    示例:

    输入: head = 1->4->3->2->5->2, x = 3
    输出: 1->2->2->4->3->5

    实现代码:
    class Solution {
    public:
        ListNode* partition(ListNode* head, int x) {
            if(head == NULL) return head; ListNode less_head(0);
            ListNode more_head(0);
            ListNode* less_ptr = &less_head;
            ListNode* more_ptr = &more_head;
            ListNode* cur = head;
            while(cur != NULL){
                if(cur->val < x){
                    less_ptr->next = cur;
                    less_ptr = less_ptr->next;
                } else{
                    more_ptr->next = cur;
                    more_ptr = more_ptr->next;
                } cur = cur->next;
            }
            less_ptr->next = more_head.next;
            more_ptr->next = NULL;
            return less_head.next;

        }
    };

    16.反转链表Ⅱ

    题目描述:
    反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

    说明:
    1 ≤ m ≤ n ≤ 链表长度。

    示例:

    输入: 1->2->3->4->5->NULL, m = 2, n = 4
    输出: 1->4->3->2->5->NULL

    实现代码:
    class Solution {
    public:
        ListNode* reverseBetween(ListNode* head, int m, int n) {
            if (head == NULL || head->next == NULL) {
                return head;
            }
            
            ListNode* dummy = new ListNode(0);
            dummy->next = head;
            
            ListNode* prev = dummy;
            for (int i = 0; i < m - 1; i++) {
                prev = prev->next;
            }
            ListNode* start = prev->next;
            ListNode* then = start->next;
            
            for (int i = 0; i < n - m; i++) {
                start->next = then->next;
                then->next = prev->next;
                prev->next = then;
                then = start->next;
            }
            
            return dummy->next;
        }
    };

    17.环形链表

    题目描述:
    给定一个链表,判断链表中是否有环。

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

    实现代码:
    class Solution {
    public:
        bool hasCycle(ListNode *head) {
            ListNode *L1,*L2;
            L1=head;
            L2=head;
            while(L1!=NULL && L2 != NULL && L1->next != NULL)
            {
                L1 = L1->next->next;
                L2 = L2->next;
                if(L1 == L2)
                    return true;
            }
            return false;
        }
    };

    18.移除链表元素

    题目描述:
    删除链表中等于给定值 val 的所有节点。

    示例:

    输入: 1->2->6->3->4->5->6, val = 6
    输出: 1->2->3->4->5

    实现代码:
    class Solution {
    public:
        ListNode* removeElements(ListNode* head, int val) {
    while ((head!=NULL)&&(head->val == val))
        {
            head = head->next;
        }
        ListNode* pCurrent = head;
        if (pCurrent == NULL) return NULL;
        while (pCurrent->next!=NULL)
        {
            if (pCurrent->next->val == val)
            {
                pCurrent->next = pCurrent->next->next;
            }
            else
                pCurrent = pCurrent->next;
        }
        return head;
        }
    };

    19.回文链表

    题目描述:
    请判断一个链表是否为回文链表。

    示例 1:

    输入: 1->2
    输出: false

    示例 2:

    输入: 1->2->2->1
    输出: true

    实现代码:
    class Solution {
    public:
        bool isPalindrome(ListNode* head) {
                    int n=len(head);
            if(n==1)return true;
            ListNode*head2=head;
            for(int i=0;i<(n/2+n%2);i++){
                head2=head2->next;
            }
            head2=reverseList(head2);
            while(head2!=NULL){
                if(head->val!=head2->val) return false;
                else{head=head->next;head2=head2->next;}
            }
            return true;
        }
        int len(ListNode*head){
            int n=0;
            while(head!=NULL){
                head=head->next;
                ++n;
            }
            return n;
        }
        ListNode* reverseList(ListNode* head) {
            ListNode*pt=head;
            ListNode*temp;
            if(pt==NULL) return head;
            while(pt->next!=NULL){
                temp=pt->next;
                pt->next=pt->next->next;
                temp->next=head;
                head=temp;
            }
            return head;
        }
    };

    20.链表的中间节点

    题目描述:
    给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

    如果有两个中间结点,则返回第二个中间结点。

     

    示例 1:

    输入:[1,2,3,4,5]
    输出:此列表中的结点 3 (序列化形式:[3,4,5])
    返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
    注意,我们返回了一个 ListNode 类型的对象 ans,这样:
    ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

    示例 2:

    输入:[1,2,3,4,5,6]
    输出:此列表中的结点 4 (序列化形式:[4,5,6])
    由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

    实现代码:
    class Solution {
    public:
        ListNode* middleNode(ListNode* head) {
            ListNode*cur=head->next;
            ListNode*prev=head;
            while(cur) {
                if(cur->next) {
                    cur=cur->next->next;
                } else {
                    cur=cur->next;
                } prev=prev->next;
            }
            return prev;
        }
    };
  • 相关阅读:
    Lua笔记——8.Lua & C
    Shader笔记——5.渲染纹理
    常用工具——2.Mac
    Shader笔记——4.纹理基础
    设计模式学习笔记四:简单工厂模式抽象工厂模式工厂方法模式
    设计模式学习笔记三:策略模式和状态模式
    设计模式学习笔记二:单例模式
    设计模式学习笔记一:程序设计原则
    数据结构和算法学习笔记十六:红黑树
    数据结构和算法学习笔记十五:多路查找树(B树)
  • 原文地址:https://www.cnblogs.com/zhangfuxiao/p/11385968.html
Copyright © 2020-2023  润新知