剑指offer面试常考手撸算法题-链表篇

1. 从头到尾打印链表

 class Solution {
public:
// 可以先压栈,再出栈到vector
// 时间/空间:O(n)
vector<int> printListFromTailToHead(ListNode* head) {
if(head == nullptr)
return {};
vector<int> res;
stack<int> s;
while(head != nullptr)
{
s.push(head->val);
head = head->next;
}
while(!s.empty())
{
res.push_back(s.top());
s.pop();
}
return res;
}
// 可以直接插入vector中,翻转vector
// 时间/空间:O(n)
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> res;
if(head == nullptr)
return {};
while(head)
{
res.push_back(head->val);
head = head->next;
}
reverse(res.begin(), res.end());
return res;
}
};

2. 链表中倒数第k个节点

 class Solution {
public:
//快慢指针,快指针先走k-1步,之后一起走,直到快指针到达链表尾。
//时间:O(n), 空间O(1)
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead == nullptr || k == )
return nullptr;
auto p = pListHead;
for(int i=; i<k-; i++)
{
if(p->next == nullptr)
return nullptr;
p = p->next;
}
while(p->next != nullptr)
{
p = p->next;
pListHead = pListHead->next;
}
return pListHead;
}
};

3. 翻转链表

 class Solution {
public:
//一个取巧的方法(如果允许使用额外空间):先遍历链表用栈存储元素值,然后重新遍历链表,将链表值置为栈顶。
//时间:O(n), 空间O(n)
ListNode* ReverseList(ListNode* pHead) {
stack<int> s;
auto p = pHead, q = pHead;
while(pHead != nullptr)
{
s.push(pHead->val);
pHead = pHead->next;
}
while(p != nullptr)
{
p->val = s.top();
s.pop();
p = p->next;
}
return q;
}
};
 class Solution {
public:
//2. 真正地翻转链表,交换地址
ListNode* ReverseList(ListNode* pHead) {
if(pHead == nullptr)
return nullptr;
decltype(pHead) pre = nullptr;
auto next = pre;
ListNode *res = nullptr;
while(pHead != nullptr)
{
next = pHead->next;
if(next == nullptr)
res = pHead;
pHead->next = pre;
pre = pHead;
pHead = next;
}
return res;
}
};

4. 合并两个排序链表

 class Solution {
public:
//非递归版本:双指针分别遍历两个链表
ListNode* Merge1(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == nullptr)
return pHead2;
if(pHead2 == nullptr)
return pHead1;
ListNode *head = new ListNode();
head->next = nullptr;
ListNode *res = head;
while(pHead1 != nullptr && pHead2 != nullptr)
{
if(pHead1->val <= pHead2->val)
{
head->next = pHead1;
head = head->next;
pHead1 = pHead1->next;
}
else
{
head->next = pHead2;
head = head->next;
pHead2 = pHead2->next;
}
}
if(pHead1 != nullptr)
head->next = pHead1;
else
head->next = pHead2;
return res->next;
}
//递归版本
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == nullptr)
return pHead2;
if(pHead2 == nullptr)
return pHead1; ListNode* head = nullptr;
if(pHead1->val <= pHead2->val)
{
head = pHead1;
head->next = Merge(pHead1->next, pHead2);
}
else
{
head = pHead2;
head->next = Merge(pHead2->next, pHead1);
}
return head;
}
};

5. 两个链表第一个公共节点

 class Solution {
public:
//暴力法太低级,O(n2)不可接受
//使用unordered_map存储一个链表节点吧,时间O(n),空间O(n)
//unordered_map使用[]/insert插入,不是push_back()
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
if(pHead1 == nullptr)
return nullptr;
if(pHead2 == nullptr)
return nullptr; unordered_map<int, ListNode*> ump;
while(pHead1 != nullptr)
{
ump.insert({pHead1->val, pHead1});
pHead1 = pHead1->next;
}
while(pHead2 != nullptr)
{
auto res = ump.find(pHead2->val);
if(res != ump.end())
return res->second;
pHead2 = pHead2->next;
}
return nullptr;
}
};

6. 链表中环的入口节点(快2满1指针判断成环,再走一圈计算环长,快慢指针找到入口)

判断链表是否成环(快慢指针解决)

 /*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
//判断成环及入口:快慢指针
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode *pMeet = judgeLoop(pHead);
if(pMeet == nullptr)//未成环
return nullptr;
auto p = pMeet;
int loopLen = ;
//计算环长,相遇点再走一圈
while(p->next != pMeet)
{
p = p->next;
loopLen++;
}
auto q = pHead;
//后指针先走环长
while(loopLen--)
{
q = q->next;
}
//快慢一起走
p = pHead;
while(p != q)
{
p = p->next;
q = q->next;
}
return p;
}
//判断是否成环,快指针走两步-慢指针走一步,指针相遇必在环内
ListNode* judgeLoop(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
auto pSlow = pHead->next;
if(pSlow == nullptr)
return nullptr;
auto pFast = pSlow->next;
while(pSlow != nullptr && pFast != nullptr)
{
if(pSlow == pFast)
return pSlow;
pSlow = pSlow->next;
pFast = pFast->next;
if(pFast != nullptr)
pFast = pFast->next;
}
return nullptr;
}
};

7. 删除链表重复节点(重复保留一个)

 class Solution {
public:
//一次遍历,前后节点值相等,删除后一节点
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
auto pre = pHead;
auto cur = pre->next;
while(cur != nullptr)
{
while(cur->val == pre->val)
{
pre->next = cur->next;
cur = pre->next;
if(cur == nullptr)
return pHead;
}
pre = cur;
cur = cur->next;
}
return pHead;
}
};

8. 删除链表重复节点(重复节点不保留)

 class Solution {
public:
/*创建一个头节点,它的next指向链表头,然后再用两个指针
一前一后来遍历链表,后一个指针判断有无重复并进行后移*/
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode *first = new ListNode();
first->next = pHead;
ListNode *last = first;
ListNode *p = pHead;
while(p != nullptr && p->next != nullptr)
{
if(p->val == p->next->val)//有重复,需要删除
{
int val = p->val;
while(p != nullptr && p->val == val)
p = p->next;
last->next = p;
}
else
{
last = p;
p = p->next;
}
}
return first->next;
}
};

9. 判断两个链表是否交叉

(同样可使用一个unordered_map来存储一个链表中的节点指针,再遍历另外一个链表逐个查找)

 bool FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
if(pHead1 == nullptr || pHead2 == nullptr)
return false;
unordered_map<ListNode*, int> ump;
while(pHead1 != nullptr)
{
ump.insert({pHead1, pHead1->val});
pHead1 = pHead1->next;
}
while(pHead2 != nullptr)
{
auto res = ump.find(pHead2);
if(res != ump.end())
return true;
pHead2 = pHead2->next;
}
return false;
}

10.相交链表

O(n)

 class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
auto p = headA, q = headB;
while(p != q)
{
if(p == q)
return p;
p = (p == nullptr) ? headB : p->next;
q = (q == nullptr) ? headA : q->next;
}
return p;
}
};

说明:以上其他题目代码由牛客oj/leetcode通过,第9个未测试。

11.删除链表第n个节点(leetcode 19)

O(n)

 class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int len = ;
auto p = head;
while(p != nullptr)//计算表长
{
len++;
p = p->next;
}
if(n > len)//边界处理
return nullptr; len = len-n-;//先走len-n-1步
p = head;
if(len < )//删除头节点
return p->next; while(len--)//删除其他节点
p = p->next;
p->next = p->next->next;
return head;
}
};

the end.

剑指offer-链表相关的更多相关文章

  1. 剑指offer——链表相关问题总结

    首先统一链表的数据结构为: struct ListNode { int val; struct ListNode *next; ListNode(int x) :val(x), next(NULL) ...

  2. 剑指Offer 链表中倒数第k个结点

    题目描述 输入一个链表,输出该链表中倒数第k个结点.     思路: 法1:设置2个指针p,q.p先移动k次,然后pq同时后移,p到链表尾尾的时候,q指向倒数第k个节点. 注意://需要考虑k=0,以 ...

  3. 剑指offer——链表中倒数第k个结点

    输入一个链表,输出该链表中倒数第k个结点. class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned ...

  4. 剑指Offer——链表中环的入口结点

    题目描述: 一个链表中包含环,请找出该链表的环的入口结点. 分析: 设置两个指针p1,p2, 两个指针都从链表的头部开始走,不过p1每次走一步,p2每次走两步. 直到相遇的时候,p2走的长度是p1的两 ...

  5. 剑指Offer——链表中倒数第k个节点

    Question 输入一个链表,输出该链表中倒数第k个结点. Solution 一种想法就是扫描两边,第一遍求出总的节点个数,第二遍从头开始走n-k个 第二种思想类似于fast-slow指针的方法,f ...

  6. python剑指offer 链表中环的入口节点

    题目: 一个链表中包含环,请找出该链表的环的入口结点. 思路: 先说个定理:两个指针一个fast.一个slow同时从一个链表的头部出发, fast一次走2步,slow一次走一步,如果该链表有环,两个指 ...

  7. acwing 70-72 剑指OFFER 二叉树相关

    地址 https://www.acwing.com/problem/content/66/ https://www.acwing.com/problem/content/67/ https://www ...

  8. 用js刷剑指offer(链表中倒数第k个结点)

    题目描述 输入一个链表,输出该链表中倒数第k个结点. 牛客网链接 思路 设置两个指针,p,q,先让p走k-1步,然后再一起走,直到p为最后一个 时,q即为倒数第k个节点 js代码 // 空间复杂度1 ...

  9. 剑指offer 链表中环的入口位置

    题目描述 一个链表中包含环,请找出该链表的环的入口结点.   思路:这题需要知道a = c,然后head和slow每次走一步,相遇的时候就是第一个入口交点, 注意:for循环或者while循环之后,一 ...

  10. 剑指offer 链表中倒数第K个节点

    利用两个间隔为k的指针来实现倒数第k个 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ...

随机推荐

  1. ES6深入浅出-7 新版的类(上集)-1.介绍原型

    ES6新出的关键class BE受雇与网景开发了JS 当我们在写一个对象的时候,我们实际上内存的形式表示. obj等于一个空对象,可以直接toString.它为什么可以有toString window ...

  2. Python基础教程(第2版 修订版) pdf

    Python基础教程(第2版 修订版) 目录 D11章快速改造:基础知识11.1安装Python11.1.1Windows11.1.2Linux和UNIX31.1.3苹果机(Macintosh)41. ...

  3. 报错:java.lang.ClassNotFoundException: org.codehaus.jackson.map.JsonMappingException

    报错背景: 执行hdfs-mysql的job任务的时候报错. 报错现象: Exception has occurred during processing command Exception: org ...

  4. LeetCode_226. Invert Binary Tree

    226. Invert Binary Tree Easy Invert a binary tree. Example: Input: 4 / \ 2 7 / \ / \ 1 3 6 9 Output: ...

  5. [ kvm ] 嵌套虚拟化

    1. 前言 在学习 kvm 的过程中,需要在虚拟机中再次开启虚拟机,这里就需要使用到嵌套虚拟化,做个记录吧. 2. 配置嵌套虚拟化 2.1 查看物理机是否支持嵌套虚拟化 cat /sys/module ...

  6. IIS+PHP本地开发环境配置

    打开Win7系统自带IIS.如图只要点击两下,CGI一定要勾选上!完成后打开浏览器输入127.0.0.1测试一下,如果能打开页面说明iis开启成功. 安装PHP.不同版本的PHP会有所不同,这里使用的 ...

  7. maven 中配置多个mirror的问题

    公司搭建的maven私服做镜像,有使用aliyun的镜像,还有其他地方的, 默认情况下配置多个mirror的情况下,只有第一个生效.那么我们可以将最后一个作为默认值,前面配置的使用环境变量动态切换. ...

  8. velocity 自定义工具类接入

    网上的教程几乎都是同一篇: velocity 自定义工具类 - eggtk - CSDN 博客 但是教程有不完善的地方,我就补充一下. 补充: 引入的jar包和版本要一致.我们项目中因为没有定义确切版 ...

  9. IntelliJ IDEA 下搭建vue项目工程

    Vue 项目:运行 npm run dev  后报错 “'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序 或批处理文件.” 前提: 电脑已经安装了node 和 npm, ...

  10. ip网络