剑指offer-链表相关
剑指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-链表相关的更多相关文章
- 剑指offer——链表相关问题总结
首先统一链表的数据结构为: struct ListNode { int val; struct ListNode *next; ListNode(int x) :val(x), next(NULL) ...
- 剑指Offer 链表中倒数第k个结点
题目描述 输入一个链表,输出该链表中倒数第k个结点. 思路: 法1:设置2个指针p,q.p先移动k次,然后pq同时后移,p到链表尾尾的时候,q指向倒数第k个节点. 注意://需要考虑k=0,以 ...
- 剑指offer——链表中倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点. class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned ...
- 剑指Offer——链表中环的入口结点
题目描述: 一个链表中包含环,请找出该链表的环的入口结点. 分析: 设置两个指针p1,p2, 两个指针都从链表的头部开始走,不过p1每次走一步,p2每次走两步. 直到相遇的时候,p2走的长度是p1的两 ...
- 剑指Offer——链表中倒数第k个节点
Question 输入一个链表,输出该链表中倒数第k个结点. Solution 一种想法就是扫描两边,第一遍求出总的节点个数,第二遍从头开始走n-k个 第二种思想类似于fast-slow指针的方法,f ...
- python剑指offer 链表中环的入口节点
题目: 一个链表中包含环,请找出该链表的环的入口结点. 思路: 先说个定理:两个指针一个fast.一个slow同时从一个链表的头部出发, fast一次走2步,slow一次走一步,如果该链表有环,两个指 ...
- acwing 70-72 剑指OFFER 二叉树相关
地址 https://www.acwing.com/problem/content/66/ https://www.acwing.com/problem/content/67/ https://www ...
- 用js刷剑指offer(链表中倒数第k个结点)
题目描述 输入一个链表,输出该链表中倒数第k个结点. 牛客网链接 思路 设置两个指针,p,q,先让p走k-1步,然后再一起走,直到p为最后一个 时,q即为倒数第k个节点 js代码 // 空间复杂度1 ...
- 剑指offer 链表中环的入口位置
题目描述 一个链表中包含环,请找出该链表的环的入口结点. 思路:这题需要知道a = c,然后head和slow每次走一步,相遇的时候就是第一个入口交点, 注意:for循环或者while循环之后,一 ...
- 剑指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 ...
随机推荐
- osg编译日志
1>------ 已启动全部重新生成: 项目: ZERO_CHECK, 配置: Debug x64 ------1> Checking Build System1> CMake do ...
- 深入学习c++--lambda函数
1. 简单使用 #include <iostream> #include <functional> using namespace std; struct Print { vo ...
- ES6深入浅出-12 ES6新增的API(下)-1.录屏
String.includes es5里面判断字符串是否存在的方法 search searcg的厉害之处是可以使用正则 match正则的方式 repeat -1遍,就不合法 startsWith 判断 ...
- ES6深入浅出-3 三个点运算 & 新版字符串-1.函数与对象的语法糖
主要讲的内容 时间充裕的话就讲,模板字面量 默认参数值 首先讲es6之前,我们是怎么做的.例如我们要写一个求和的函数, 请两个参数的和,但是如果有的人就是穿一个参数呢? 那么b没有传值,b的值是多少呢 ...
- VMWare-Linux NAT模式联网配置
VMWare-Linux NAT模式联网配置 摘自:https://blog.csdn.net/a56112777/article/details/83053566 (注意使用root用户) 1. ...
- SQL查询优化 LEFT JOIN和INNER JOIN
作者:VerySky 推荐:陈敬(Cathy) SQL查询优化 LEFT JOIN和INNER JOIN 1,连接了八个数据库表,而且全部使用LEFT JOIN,如下所示: Resource_Reso ...
- 无法复制CSD内容,复制后出现一行长字符串解决
先打开一个linux文件,然后把复制的内容放到linux文件中即可解决
- vi 替换命令 以及“找不到模式”解决
转自:https://www.cnblogs.com/zfyouxi/p/5181363.html 在linux vi编辑工具中使用替换命令操作时,会出现明明有匹配查找模式的数据.却报“找不到模式”问 ...
- Jupyter notbook 修改默认路径
打开 cmd 输入命令 jupyter notebook --generate-config 2.打开配置文件 3.修改路径 转自: https://blog.csdn.net/zw__chen ...
- [转载]SQL Server提权系列
本文原文地址:https://www.cnblogs.com/wintrysec/p/10875232.html 一.利用xp_cmdshell提权 xp_cmdshell默认是关闭的,可以通过下面的 ...