文章目录
剑指offer 03——从尾到头打印链表
题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
输入
{67,0,24,58}
返回值
[58,24,0,67]
解题思路
使用递归
代码
void PrintOP(ListNode* node, vector<int> &res) {
if(!node)
return;
PrintOP(node->next, res);
res.push_back(node->val);
}
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> res;
PrintOP(head, res);
return res;
}
剑指offer 14——链表中倒数第K个节点
题目描述
输入一个链表,输出该链表中倒数第k个结点。
如果该链表长度小于k,请返回空。输入
{1,2,3,4,5},1
返回值
{5}
解题思路
快慢指针
快指针先向后走k步
快慢指针每次各走一步
快指针为空,返回满指针
代码
ListNode* FindKthToTail(ListNode* pHead, int k) {
// write code here
if(!pHead) return pHead;
ListNode* fast = pHead;
ListNode* slow = pHead;
while(k-- && fast){
fast = fast -> next;
}
//k大于链表长度返回空值
if(k >= 0) return nullptr;
while(fast){
fast = fast -> next;
slow = slow -> next;
}
return slow;
}
剑指offer 15——反转链表
题目描述
输入一个链表,反转链表后,输出新链表的表头。
输入
{1,2,3}
返回值
{3,2,1}
解题思路
三指针法
代码
ListNode* ReverseList(ListNode* pHead) {
if(!pHead) return nullptr;
ListNode* pre = nullptr;
ListNode* cur = pHead;
ListNode* next = nullptr;
while(cur){
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
剑指offer 16——合并两个排序的链表
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
输入
{1,3,5},{2,4,6}
返回值
{1,2,3,4,5,6}
解题思路
定义一个前驱节点(哨兵)和遍历节点,
遍历节点每次指向值最小的节点
当有一个链表为空跳出循环
遍历节点的next指向不为空的链表
代码
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
//哨兵节点
ListNode* n1 = new ListNode(-1);
ListNode* n2 = n1;
while(pHead1 && pHead2) {
if(pHead1 -> val < pHead2 -> val) {
n2->next = pHead1;
pHead1 = pHead1 ->next;
}
else {
n2 -> next = pHead2;
pHead2 = pHead2 -> next;
}
n2 = n2 -> next;
}
//指向仍有剩余节点的链表
n2 ->next = pHead1 ? pHead1 : pHead2;
return n1 -> next;
}
剑指offer 25——复杂链表的复制
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
解题思路
1.复制节点
2.复制节点random关系
3.断开原链表与复制链表
具体过程参考下面代码:
代码
RandomListNode* Clone(RandomListNode* pHead) {
if(!pHead) return nullptr;
RandomListNode* ret = nullptr;
RandomListNode* node = pHead;
//1.创建节点
while(node) {
RandomListNode* tmp = new RandomListNode(node->label);
tmp->next = node->next;
node->next = tmp;
node = tmp->next;
}
node = pHead;
//2.复制random关系
while(node) {
//注意加上空结点的判断,否则会出现段错误
node->next->random = node->random ? node ->random ->next : nullptr;
node = node->next->next;
}
//3.断开链表,返回复制链表
node = pHead;
ret = pHead->next;
while(node) {
RandomListNode* tmp = node -> next;
node -> next = tmp ? tmp -> next : nullptr;
node = node -> next;
tmp -> next = node ? node -> next : nullptr;
}
return ret;
}
剑指offer 36——两个链表的第一个公共节点
题目描述
输入两个链表,找出它们的第一个公共结点。
解题思路
设两个链表分别为L1、L2。表头节点为n1、n2。
n1和n2到公共节点的距离是不一定相等的,我们需要加以调整,使他们到公共节点的距离一致
具体操作:A尾节点指向B头,B尾节点指向A头,这样他们第二次一定会相遇。
代码
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode *n1 = pHead1, *n2 = pHead2;
while(n1 != n2){
n1 = n1 ? n1 -> next : pHead2;
n2 = n2 ? n2 -> next : pHead1;
}
return n1;
}
剑指offer 55——链表中环的入口结点
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路
快慢指针
快指针、慢指针同时指向头节点,快指针一次走两步,慢指针一次走一步
相遇后,快指针指向头节点,然后快慢指针每次走一步,第二次相遇的点即为环的入口节点
代码
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* fast = pHead;
ListNode* slow = pHead;
//快指针每次两步,慢指针每次一步
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast == slow) break;
}
//是否有环判断
if(!fast || !fast->next) return nullptr;
fast = pHead;
//如果有环,就一定能找到进入节点
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return fast;
}
剑指offer 56——删除链表中的重复节点
题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
输入
{1,2,3,3,4,4,5}
返回值
{1,2,5}
解题思路
直接删除法
在遍历单链表的时候,检查当前节点与下一点是否为相同值,如果相同,继续查找祥同值的最大长度,然后指针改变指向。
代码
ListNode* deleteDuplication(ListNode* pHead) {
//哨兵结点
ListNode* vHead = new ListNode(-1);
vHead -> next = pHead;
ListNode* pre = vHead, *cur = pHead;
while(cur){
//找相同的连续结点
if(cur->next && cur->val == cur->next->val) {
cur = cur -> next;
while(cur->next && cur ->val == cur ->next->val) {
cur = cur -> next;
}
//当前不等于下一个,因此继续后移一位
cur = cur -> next;
pre ->next = cur;
}
else {
pre = cur;
cur = cur -> next;
}
}
return vHead -> next;
}