链表相关问题

    xiaoxiao2022-07-12  142

    链表中的倒数第k个结点

    输入一个链表,输出该链表中倒数第k个结点。

    思路

    在牛客网上看到一个很巧妙的方法。设置两个指针p,q。其中q先移动k-1步,然后p和q一起往后移,直至q移动到链表末尾。此时p指向的元素即为倒数第k个元素。

    /* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { ListNode* p=pListHead; ListNode* q=pListHead; unsigned int count=0; while(p!=NULL&&count!=k-1){ p=p->next; count++; } if(p==NULL) return NULL; else{ while(p->next!=NULL){ p=p->next; q=q->next; } } return q; } };

    合并两个排序的链表

    输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

    思路1(非递归)

    创建一个头结点t_head(方便返回)和一个pre指针,pre指针一开始指向头结点t_head。比较l1,l2此时指向的结点值的大小,比如此时l1->val<=l2->val,那么将l1接在pre的后面,l1后移,pre后移;l2同理。循环直到l1或l2为空,再把剩余元素接到pre后面,返回头结点t_head的下一个结点即可。

    /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* t_head=new ListNode(-1); ListNode* pre=t_head; while(l1!=NULL&&l2!=NULL){ if(l1->val<=l2->val){ pre->next=l1; l1=l1->next; } else{ pre->next=l2; l2=l2->next; } pre=pre->next; } pre->next=l1==NULL?l2:l1; return t_head->next; } };

    思路2(递归)

    按两列表当前结点的大小关系递归两列表,借助递归栈保存之前结点的递归顺序,在递归结束返回时,按之前递归的顺序返回结点指针,最终将两链表串为一个有序的链表。

    /* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { if(pHead1==NULL) return pHead2; if(pHead2==NULL) return pHead1; if(pHead1->val>pHead2->val){ pHead2->next=Merge(pHead1,pHead2->next); return pHead2; } else{ pHead1->next=Merge(pHead1->next,pHead2); return pHead1; } } };

    合并K个排序链表

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

    示例:

    输入: [ 1->4->5, 1->3->4, 2->6 ] 输出: 1->1->2->3->4->4->5->6

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-k-sorted-lists 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    思路

    之前想的是顺序遍历数组中每两个链表,两两合并。这样时间复杂度有点大 O ( n k ) O(nk) O(nk)(其中 n n n为链表长度, k k k为链表数量)。 后来看了LeetCode的题解,可以利用分治的想法,每一次合并 k 2 \frac{k}{2} 2k个链表,过程如下图所示。时间复杂度为 O ( n l o g 2 k ) O(nlog_2k) O(nlog2k)(其中 n n n为链表长度, k k k为链表数量)。

    代码(c++)

    /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* merge(ListNode* l1,ListNode* l2){ ListNode* head=new ListNode(-1); ListNode* pre=head; while(l1!=NULL&&l2!=NULL){ if(l1->val<=l2->val){ pre->next=l1; l1=l1->next; } else{ pre->next=l2; l2=l2->next; } pre=pre->next; } pre->next=l1==NULL?l2:l1; return head->next; } ListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.size()==0) return NULL; if(lists.size()==1) return lists[0]; int interval=1; while(interval<lists.size()){ for(int i=0;i<lists.size()-interval;i+=interval*2){ lists[i]=merge(lists[i],lists[i+interval]); } interval*=2; } return lists[0]; } };
    最新回复(0)