链表相关题目的实现
2016-05-26 21:51
417 查看
1. 环形链表的插值
有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。
测试样例:
[1,3,4,5,7],[1,2,3,4,0],2
返回:{1,2,3,4,5,7}
本质就是链表的插值
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class InsertValue { public: ListNode* insert(vector<int> A, vector<int> nxt, int val) { // write code here auto res = createList(A, nxt); return insertList(res, val); } private: // create the list ListNode * createList(vector<int> & A, vector<int> & nxt){ ListNode myhead(0); ListNode * pre = &myhead; int count = 0; int id = 0; while (count < (int)nxt.size()){ ListNode * newNode = new ListNode(A[id]); pre->next = newNode; pre = newNode; id = nxt[id]; count++; } //pre->next = myhead.next; return myhead.next; } // insert node ListNode * insertList(ListNode * head, int val){ ListNode myhead(0); myhead.next = head; ListNode * pre = &myhead; bool notfirst = false; //while (head != myhead.next || !notfirst){ while (head){ notfirst = true; if (val <= head->val){ ListNode * newNode = new ListNode(val); pre->next = newNode; newNode->next = head; return myhead.next; } else{ pre = pre->next; head = head->next; } } ListNode * newNode = new ListNode(val); pre->next = newNode; newNode->next = head; return myhead.next; } };
2. 访问单个节点的删除
实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true
把后面一个节点的值复制过来, 然后删除后面一个节点
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Remove { public: bool removeNode(ListNode* pNode) { // write code here if (!pNode || !pNode->next) return false; pNode->val = pNode->next->val; pNode->next = pNode->next->next; return true; } };
3. 链表的分化
对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。
测试样例:
{1,4,2,5},3
{1,2,4,5}
分割成三段链表, 注意连接时候, 空链的判断
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Divide { public: ListNode* listDivide(ListNode* head, int val) { // write code here if (!head) return nullptr; ListNode lower(0), higher(0), equal(0); ListNode * preLower = &lower, *preHigher = &higher, *preEqual = &equal; while (head){ if (head->val < val){ preLower->next = head; preLower = head; head = head->next; preLower->next = nullptr; } else if (head->val > val){ preHigher->next = head; preHigher = head; head = head->next; preHigher->next = nullptr; } else{ preEqual->next = head; preEqual = head; head = head->next; preEqual->next = nullptr; } } if (lower.next){ preEqual->next = lower.next; preLower->next = higher.next; } else{ preEqual->next = higher.next; } return equal.next; } };
4. 打印两个链表的公共值
现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值
测试样例:
{1,2,3,4,5,6,7},{2,4,6,8,10}
返回:[2.4.6]
类似归并排序的排序过程
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Common { public: vector<int> findCommonParts(ListNode* headA, ListNode* headB) { // write code here vector<int> res; while (headA && headB){ if (headA->val == headB->val){ res.push_back(headA->val); headA = headA->next; headB = headB->next; } else if (headA->val < headB->val){ headA = headA->next; } else{ headB = headB->next; } } return res; } };
5. 链表的k逆序
有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。
本质: 链表逆序
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class KInverse { public: ListNode* inverse(ListNode* head, int k) { // write code here ListNode myhead(0); myhead.next = head; ListNode * pre = &myhead; int count = 1; while (head){ head = head->next; count++; if (count >= k && head){ ListNode * nextEnd = pre->next; ListNode * cur = pre->next; ListNode * nextstart = head->next; ListNode * precur = head->next; while (cur != nextstart){ ListNode * next = cur->next; cur->next = precur; precur = cur; cur = next; } pre->next = head; count = 1; pre = nextEnd; head = nextstart; } } return myhead.next; } };
6. 链表指定值清除
现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。
测试样例:
{1,2,3,4,3,2,1},2
{1,3,4,3,1}
本质: 链表删除节点
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class ClearValue { public: ListNode* clear(ListNode* head, int val) { // write code here ListNode myhead(0); ListNode * pre = &myhead; myhead.next = head; while (head){ if (head->val == val){ pre->next = head->next; head = pre->next; } else{ pre = pre->next; head = head->next; } } return myhead.next; } };
7. 链表回文结构
请编写一个函数,检查链表是否为回文。给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。
测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false
本质: 快慢指针分割链表, 链表逆序
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Palindrome { public: bool isPalindrome(ListNode* pHead) { // write code here ListNode * left = pHead, * right = nullptr; divide(left, right); right = reverse(right); while (left && right){ if (left->val != right->val) return false; left = left->next; right = right->next; } return true; } private: void divide(ListNode * & left, ListNode * & right){ ListNode myhead(0); myhead.next = left; ListNode * l1 = &myhead, *l2 = &myhead; while (l2 && l2->next){ l1 = l1->next; l2 = l2->next->next; } right = l1->next; l1->next = nullptr; } ListNode * reverse(ListNode * right){ ListNode * pend = nullptr; while (right){ ListNode * next = right->next; right->next = pend; pend = right; right = next; } return pend; } };
8. 复杂链表复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。leetcode 上的一道经典题目
/* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; */ class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { RandomListNode * start = pHead; // clone while (pHead){ RandomListNode * newNode = new RandomListNode(pHead->label); newNode->next = pHead->next; pHead->next = newNode; pHead = pHead->next->next; } // modify random pointer pHead = start; while (pHead){ if (pHead->random) pHead->next->random = pHead->random->next; pHead = pHead->next->next; } // split RandomListNode myhead(0); RandomListNode * pre = &myhead; pHead = start; while (pHead){ RandomListNode * tmp = pHead->next; pHead->next = tmp->next; pre->next = tmp; pre = tmp; pHead = pHead->next; } return myhead.next; } };
9. 链表判环
如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。
本质: 快慢指针
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class ChkLoop { public: int chkLoop(ListNode* head, int adjust) { // write code here ListNode myhead(0); myhead.next = head; ListNode *p1 = head, *p2 = head; while (p2 && p2->next){ p1 = p1->next; p2 = p2->next->next; // has loop if (p1 == p2){ p1 = myhead.next; while (p1 != p2){ p1 = p1->next; p2 = p2->next; } return p1->val; } } return -1; } };
10. 无环单链表判相交
现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,判断这两个链表是否相交。给定两个链表的头结点headA和headB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。
本质:将两个链表统一成一样长度比较
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class CheckIntersect { public: bool chkIntersect(ListNode* headA, ListNode* headB) { // write code here int lenA = 0; ListNode * pA = headA, *pB = headB; while (headA){ lenA++; headA = headA->next; } int lenB = 0; while (headB){ lenB++; headB = headB->next; } if (lenA > lenB){ int gap = lenA - lenB; headA = pA; headB = pB; while (gap){ headA = headA->next; gap--; } } else if (lenA < lenB){ int gap = lenB - lenA; headB = pB; headA = pA; while (gap){ headB = headB->next; gap--; } } while (headA && headB){ if (headA == headB) return true; headA = headA->next; headB = headB->next; } return false; } };
11. 有环单链表相交判断
如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。如果两个链表长度分别为N和M,请做到时间复杂度O(N+M),额外空间复杂度O(1)。给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。
区分两种情况:
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class ChkIntersection { public: bool chkInter(ListNode* head1, ListNode* head2, int adjust0, int adjust1) { // write code here ListNode * p1 = chkLoop(head1); ListNode * p2 = chkLoop(head2); if (p1 == p2){ //ListNode * res = chkIntersect(head1, head2, p1); return true; } else{ ListNode * pcur = p1; bool flag = false; while (pcur != p1 || !flag){ flag = true; pcur = pcur->next; if (pcur == p2) return true; } return false; } } private: ListNode * chkLoop(ListNode* head) { // write code here ListNode myhead(0); myhead.next = head; ListNode *p1 = head, *p2 = head; while (p2 && p2->next){ p1 = p1->next; p2 = p2->next->next; // has loop if (p1 == p2){ p1 = myhead.next; while (p1 != p2){ p1 = p1->next; p2 = p2->next; } return p1; } } return nullptr; } };
12. 单链表相交判断
给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。
本质: 上面几种讨论情形的综合情况
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class ChkIntersection { public: bool chkInter(ListNode* head1, ListNode* head2, int adjust0, int adjust1) { // write code here ListNode * p1 = chkLoop(head1); ListNode * p2 = chkLoop(head2); if (p1 && !p2 || !p1 && p2) return false; else if (!p1 && !p2){ ListNode * res = chkIntersect(head1, head2, nullptr); return res ? true : false; } else{ if (p1 == p2){ //ListNode * res = chkIntersect(head1, head2, p1); return true; } else{ ListNode * pcur = p1; bool flag = false; while (pcur != p1 || !flag){ flag = true; pcur = pcur->next; if (pcur == p2) return true; } return false; } } } private: ListNode * chkLoop(ListNode* head) { // write code here ListNode myhead(0); myhead.next = head; ListNode *p1 = head, *p2 = head; while (p2 && p2->next){ p1 = p1->next; p2 = p2->next->next; // has loop if (p1 == p2){ p1 = myhead.next; while (p1 != p2){ p1 = p1->next; p2 = p2->next; } return p1; } } return nullptr; } ListNode * chkIntersect(ListNode* headA, ListNode* headB, ListNode * pend) { // write code here int lenA = 0; ListNode * pA = headA, *pB = headB; while (headA != pend){ lenA++; headA = headA->next; } int lenB = 0; while (headB != pend){ lenB++; headB = headB->next; } if (lenA > lenB){ int gap = lenA - lenB; headA = pA; headB = pB; while (gap){ headA = headA->next; gap--; } } else if (lenA < lenB){ int gap = lenB - lenA; headB = pB; headA = pA; while (gap){ headB = headB->next; gap--; } } while (headA != pend && headB != pend){ if (headA == headB) return headA; headA = headA->next; headB = headB->next; } return nullptr; } };
相关文章推荐
- [C/C++]反转链表
- C#实现基于链表的内存记事本实例
- C#模拟链表数据结构的实例解析
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++利用静态成员或类模板构建链表的方法讲解
- C++实现简单的学生管理系统
- Linux内核链表实现过程
- C++链表倒序实现方法
- C#通过链表实现队列的方法
- C#实现的简单链表类实例
- 找出链表倒数第n个节点元素的二个方法
- Java数据结构之简单链表的定义与实现方法示例
- Java模拟有序链表数据结构的示例
- C语言单循环链表的表示与实现实例详解
- C++实现的链表类实例
- PHP小教程之实现链表
- PHP中模拟链表和链表的基本操作示例
- C语言双向链表的表示与实现实例详解
- js链表操作(实例讲解)
- C语言实现输出链表中倒数第k个节点