版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk_bjut_edu_cn/article/details/83583103
剑指Offer(6)--从尾到头打印链表
#include<stack>
#include<iostream>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
};
//用stack实现的,而递归本质上就是一个栈结构,所以也可以用递归来实现
void printListReversing_1(ListNode *node)
{
stack<ListNode*> sList;
while (node != nullptr)
{
sList.push(node);
node = node->m_next;
}
while (!sList.empty())
{
cout << sList.top()->m_value << " ";
sList.pop();
}
}
//用递归的方式实现
void printListReversing_2(ListNode *node)
{
if (node != nullptr)
{
if (node->m_next != nullptr)
printListReversing_2(node->m_next);
cout << node->m_value << " ";
}
}
剑指Offer(22)--链表中倒数第k个节点
#include<iostream>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
};
/*
输入一个链表,输出该链表中倒数第k个节点
*/
//分成两个指针走,使它俩的距离相差k-1
int printListNode(ListNode *node, int k)
{
if (node == nullptr || k <= 0)
return -1;
ListNode *firstNode = node;
ListNode *secondNode = node;
for (int i = 0; i < k-1; ++i)
{
if (firstNode->m_next == nullptr)
{
cout << "链表个数小于k" << endl;
return -1;
}
firstNode = firstNode->m_next;
}
while (firstNode->m_next != nullptr)
{
firstNode = firstNode->m_next;
secondNode = secondNode->m_next;
}
return secondNode->m_value;
}
int main(void)
{
ListNode *m_node1 = new ListNode();
ListNode *m_node2 = new ListNode();
ListNode *m_node3 = new ListNode();
ListNode *m_node4 = new ListNode();
m_node1->m_value = 1;
m_node1->m_next = m_node2;
m_node2->m_value = 2;
m_node2->m_next = m_node3;
m_node3->m_value = 3;
m_node3->m_next = m_node4;
m_node4->m_value = 4;
m_node4->m_next = nullptr;
int result = printListNode(m_node1,5);
cout << result;
system("pause");
return 0;
}
剑指Offer(24)--反转链表
#include<iostream>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
};
/*
用三个指针解决问题
*/
ListNode *reverseList(ListNode *node)
{
if (node == nullptr || node->m_next == nullptr)
return nullptr;
ListNode *preNode = node;
ListNode *currentNode = node->m_next;
ListNode *nextNode = nullptr;
preNode->m_next = nullptr;
while (currentNode != nullptr)
{
nextNode = currentNode->m_next;
currentNode->m_next = preNode;
preNode = currentNode;
currentNode = nextNode;
}
return preNode;
}
void printListValue(ListNode *node)
{
while (node != nullptr)
{
cout << node->m_value << " ";
node = node->m_next;
}
cout << endl;
}
int main(void)
{
ListNode *m_node1 = new ListNode();
ListNode *m_node2 = new ListNode();
ListNode *m_node3 = new ListNode();
ListNode *m_node4 = new ListNode();
ListNode *m_node5 = new ListNode();
m_node1->m_value = 1;
m_node1->m_next = m_node2;
m_node2->m_value = 2;
m_node2->m_next = m_node3;
m_node3->m_value = 3;
m_node3->m_next = m_node4;
m_node4->m_value = 4;
m_node4->m_next = nullptr;
m_node5 = reverseList(m_node1);
printListValue(m_node5);
system("pause");
return 0;
}
剑指Offer(25)--合并两个排序的链表
比如是两个递增排序的链表
#include<iostream>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
};
//递归版本
ListNode *mergeList(ListNode *node1, ListNode *node2)
{
if (node1 == nullptr)
return node2;
else if (node2 == nullptr)
return node1;
ListNode *mergeHead = nullptr;
if (node1->m_value < node2->m_value)
{
mergeHead = node1;
mergeHead->m_next = mergeList(node1->m_next, node2);
}
else
{
mergeHead = node2;
mergeHead->m_next = mergeList(node1, node2->m_next);
}
return mergeHead;
}
剑指Offer(35)--复杂链表的复制
在复杂链表中,每个节点除了有一个m_next指针指向下一个节点,还有一个m_rand指针指向链表中的任意节点或者nullptr。
#include<iostream>
#include<map>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
ListNode *m_rand;
};
/*
方法一:两个链表是通过map串起来的,原始的链表
节点作为键,copy的链表作为值,然后根据键的->next
和->rand,找值的->next和->rand
*/
ListNode *copyListWithRand1(ListNode *head)
{
map<ListNode*, ListNode*> m;
ListNode *curNode = head;
//先构造出待复制的全部结点
while (curNode != nullptr)
{
ListNode *copyNode = new ListNode();
copyNode->m_value = curNode->m_value;
m.insert(pair<ListNode*, ListNode*>(curNode, copyNode));
curNode = curNode->m_next;
}
curNode = head;
//将map中的复制过来的结点串联起来
while (curNode!= nullptr)
{
m.find(curNode)->second->m_next = m.find(curNode)->first->m_next;
m.find(curNode)->second->m_rand = m.find(curNode)->first->m_rand;
curNode = curNode->m_next;
}
return m.find(head)->second;
}
/*
方法二:不使用哈希表,利用的是在原来的
链表上插入copy的节点,找到rand之后再分开
*/
ListNode *copyListWithRand2(ListNode *head)
{
if (head == nullptr)
return nullptr;
ListNode *curNode = nullptr;
ListNode *nextNode = nullptr;
/*
比如原来是2->1->8,现在就是构成
2->2~->1->1~->8->8~,这就实现了不使用额外数据结构,
而只是使用有限个变量
*/
while (curNode != nullptr)
{
nextNode = curNode->m_next;
ListNode *copyNode = new ListNode();
copyNode->m_value = curNode->m_value;
curNode->m_next = copyNode;
copyNode->m_next = nextNode;
curNode = nextNode;
}
curNode = head;
ListNode *copyNode = nullptr;
/*
下面做的是找rand,如果2->rand=8,那么2~->rand=8~;
*/
while (curNode != nullptr)
{
//cur! = nullptr,那么cur->next必然不为nullptr,因为经过了上面的复制操作
nextNode = curNode->m_next->m_next;
copyNode = curNode->m_next;
copyNode->m_rand = curNode->m_rand != nullptr ? curNode->m_rand->m_next : nullptr;
curNode = nextNode;
}
curNode = head;
ListNode *resultHead = head->m_next;
/*
经过上面的步骤,就找到了2~、1~、8~->rand,但是现在的copy链表
和原链表是在一起2->2~->1->1~->8->8~,下面进行分割
*/
while (curNode != nullptr)
{
//cur!=nullptr,那么cur->next必然不为nullptr,因为经过了上面的复制操作
nextNode = curNode->m_next->m_next;
copyNode = curNode->m_next;
curNode->m_next = nextNode;
copyNode->m_next = nextNode != nullptr ? nextNode->m_next : nullptr;
curNode = nextNode;
}
return resultHead;
}
剑指Offer(23)--链表中环的入口节点
#include<iostream>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
};
/*
判断单链表是否有环,如果有环,返回第一个入环的节点;
如果无环,返回NULL
准备两个指针,一个是快指针,一个是慢指针;快指针一次
走两步,慢指针一次走一步。如果快指针在走的过程中遇到
NULL,直接返回无环;如果有环,快指针和慢指针一定会在
环上相遇。相遇的时候快指针回到开始处,然后快指针由一次
走两步变为一次走一步,然后快慢指针一起走,相遇的节点
即为入环的节点。
*/
ListNode *getLoopListNode(ListNode *head)
{
if (head == NULL || head->m_next == NULL || head->m_next->m_next == NULL)
return NULL;
ListNode *n1 = head->m_next;//慢指针
ListNode *n2 = head->m_next->m_next;//快指针
while (n1 != n2)
{
if (n2->m_next == NULL || n2->m_next->m_next == NULL)
return NULL;
n1 = n1->m_next;
n2 = n2->m_next->m_next;
}
n2 = head;//将n2重新指向头节点
while (n1 != n2)
{
n1 = n1->m_next;
n2 = n2->m_next;
}
return n1;
}
剑指Offer(52)--两个链表的第一个公共节点
需要考虑链表是否有环,可以问面试者
#include<iostream>
using namespace std;
/*
两个单链表相交的一系列问题
【题目】 在本题中,单链表可能有环,也可能无环。给定两个
单链表的头节点 head1和head2,这两个链表可能相交,也可能
不相交。请实现一个函数, 如果两个链表相交,请返回相交的
第一个节点;如果不相交,返回null 即可。 要求:如果链表1
的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外
空间复杂度请达到O(1)。
*/
struct ListNode
{
int m_value;
ListNode *m_next;
};
/*
判断单链表是否有环,如果有环,返回第一个入环的节点;
如果无环,返回NULL
准备两个指针,一个是快指针,一个是慢指针;快指针一次
走两步,慢指针一次走一步。如果快指针在走的过程中遇到
NULL,直接返回无环;如果有环,快指针和慢指针一定会在
环上相遇。相遇的时候快指针回到开始处,然后快指针由一次
走两步变为一次走一步,然后快慢指针一起走,相遇的节点
即为入环的节点。
*/
ListNode *getLoopListNode(ListNode *head)
{
if (head == NULL || head->m_next == NULL || head->m_next->m_next == NULL)
return NULL;
ListNode *n1 = head->m_next;//慢指针
ListNode *n2 = head->m_next->m_next;//快指针
while (n1 != n2)
{
if (n2->m_next == NULL || n2->m_next->m_next == NULL)
return NULL;
n1 = n1->m_next;
n2 = n2->m_next->m_next;
}
n2 = head;//将n2重新指向头节点
while (n1 != n2)
{
n1 = n1->m_next;
n2 = n2->m_next;
}
return n1;
}
/*
如果loop1(入环节点)为NULL并且loop2也为NULL,
说明两个链表均无环。
下面的函数是在两个链表均无环找到第一个相交的节点
首先统计链表1和链表2的长度,并且拿到它们的末节点
得到长度len1和指针end1,长度len2和指针end2,先判断
end1是否等于end2(这里的相等是指内存地址,说明是
同一个节点,而不是指值),如果相等说明相加,反之,
不相交。如果end1等于end2,说明相加,但这个节点未必
是第一个相交的节点,要找第一个相交的节点,应该是len长
的那个链表先走距离差值的节点数,然后一起走,遇到相等的
节点即为第一个相交节点
*/
ListNode *noLoop(ListNode *head1, ListNode *head2)
{
if (head1 == NULL || head2 == NULL)
return NULL;
ListNode *cur1 = head1;
ListNode *cur2 = head2;
int n1 = 1, n2 = 1;
while (cur1->m_next != NULL)
{
++n1;
cur1 = cur1->m_next;
}
while (cur2->m_next != NULL)
{
++n2;
cur2 = cur2->m_next;
}
if (cur1 != cur2)
return NULL;
int n = n1 - n2;
cur1 = head1;
cur2 = head2;
while (n > 0)
{
cur1 = cur1->m_next;
--n;
}
while (n < 0)
{
cur2 = cur2->m_next;
++n;
}
//cout << n << endl;
while (cur1 != cur2)
{
cur1 = cur1->m_next;
cur2 = cur2->m_next;
}
return cur1;
}
/*
如果一个链表有环,一个链表无环,结论是不可能相交
*/
/*
如果是两个有环链表,有三种情况
1.各自环各自的,不相交
2.先相交,然后共享同一个环
3.\ /,长得和天线宝宝一样
\ /
O
如果loop1==loop2就是上面的第二种结构,如果loop1!=loop2,
则有1、3两种情况,此时从loop1开始继续走,直到又绕回
loop1还没有loop2这样一个节点,那就是情况1,否则就是情况3
*/
ListNode *bothLoop(ListNode *head1, ListNode *loop1, ListNode *head2, ListNode *loop2)
{
ListNode *cur1 = NULL;
ListNode *cur2 = NULL;
//先各走的,然后一起环一个
if (loop1 == loop2)
{
cur1 = head1;
cur2 = head2;
int n1 = 0, n2 = 0;
while (cur1 != loop1)
{
++n1;
cur1 = cur1->m_next;
}
while (cur2 != loop2)
{
++n2;
cur2 = cur2->m_next;
}
int n = n1 - n2;
cur1 = head1;
cur2 = head2;
while (n > 0)
{
cur1 = cur1->m_next;
--n;
}
while (n < 0)
{
cur2 = cur2->m_next;
++n;
}
while (cur1 != cur2)
{
cur1 = cur1->m_next;
cur2 = cur2->m_next;
}
return cur1;
}
else
{
cur1 = loop1->m_next;
while (cur1 != loop1)
{
if (cur1 == loop2)
return loop1;
cur1 = cur1->m_next;
}
//走到这说明是第一种情况,不相交
return NULL;
}
}
//接口函数
ListNode *getIntersectListNode(ListNode *head1, ListNode *head2)
{
if (head1 == NULL || head2 == NULL) {
return NULL;
}
ListNode *loop1 = getLoopListNode(head1);
ListNode *loop2 = getLoopListNode(head2);
if (loop1 == NULL && loop2 == NULL) {
return noLoop(head1, head2);
}
if (loop1 != NULL && loop2 != NULL) {
return bothLoop(head1, loop1, head2, loop2);
}
return NULL;
}
剑指Offer(18)--删除有序链表中重复的节点
1->2->2->3->4->4->5,经过下面函数处理之后:
1->3->5
#include<iostream>
using namespace std;
struct ListNode
{
int m_value;
ListNode *m_next;
};
void DeleteDuplication(ListNode **pHead)
{
if (pHead == nullptr || *pHead == nullptr)
return;
ListNode *pPreNode = nullptr;//pPreNode指向前一个不重复的节点
ListNode *pNode = *pHead;//pNode指向待验证的节点
while (pNode != nullptr)
{
ListNode *pNext = pNode->m_next;
bool needDelete = false;
if (pNext != nullptr && pNext->m_value == pNode->m_value)
needDelete = true;
if (!needDelete)
{
pPreNode = pNode;
pNode = pNode->m_next;
}
//说明某节点的值至少重复一次
else
{
int value = pNode->m_value;
ListNode *pDelete = pNode;
while (pDelete != nullptr && pDelete->m_value == value)
{
pNext = pDelete->m_next;
delete pDelete;
pDelete = nullptr;
pDelete = pNext;
}
//头节点发生了改变(因为有重复节点)
if (pPreNode == nullptr)
*pHead = pNext;
else
pPreNode->m_next = pNext;
pNode = pNext;
}
}
}
void printList(ListNode *head)
{
while (head != nullptr)
{
cout << head->m_value << " ";
head = head->m_next;
}
cout << endl;
}
int main(void)
{
ListNode *m_ListNode1 = new ListNode();
ListNode *m_ListNode2 = new ListNode();
ListNode *m_ListNode3 = new ListNode();
ListNode *m_ListNode4 = new ListNode();
ListNode *m_ListNode5 = new ListNode();
m_ListNode1->m_value = 1;
m_ListNode1->m_next = m_ListNode2;
m_ListNode2->m_value = 1;
m_ListNode2->m_next = m_ListNode3;
m_ListNode3->m_value = 2;
m_ListNode3->m_next = m_ListNode4;
m_ListNode4->m_value = 3;
m_ListNode4->m_next = nullptr;
DeleteDuplication(&m_ListNode1);
printList(m_ListNode1);
system("pause");
return 0;
}