您的位置:首页 > 其它

链表相关题目的实现

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;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  链表