加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

链表常见题目总结

发布时间:2020-12-15 07:59:39 所属栏目:Java 来源:网络整理
导读:1.从尾到头打印链表 题目描述: 输入一个链表,返回一个反序的链表。 实现代码: class Solution { public : ???? vector int printListFromTailToHead ( ListNode * head ) { ???????? stack int nodes ; ???????? vector int result ; ???????? ListNode *

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,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3,ans.next.val = 4,ans.next.next.val = 5,以及 ans.next.next.next = NULL.

示例 2:

输入:[1,5,6]
输出:此列表中的结点 4 (序列化形式:[4,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; ??? } };

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读