剑指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 ... 
随机推荐
- 多重if结构
			package com.imooc; import java.util.Scanner; public class TypeExchange { public static void main(Str ... 
- Dart 中常用的数组操作方法总结
			这里总结了一些在 Dart 中常用的数组操作方法,以便查阅. 首先,我们准备两组数据,以方便后面使用: List<Map> students = [ { 'name': 'tom', 'a ... 
- v关于使用Glide加载图片失败时显示自己特定的图片
			Glide是Android加载图片的一个框架. 常用加载图片到imageView:Glide.with(this).load(url).into(ImageView imageview). 当加载失败 ... 
- Sqoop2 将hdfs中的数据导出到MySQL
			1.进入sqoop2终端: [root@master /]# sqoop2 2.为客户端配置服务器: sqoop:000> set server --host master --port 120 ... 
- array_map
			<?php //对数组中的每个元素做函数处理 $arr = array(,,,,,); function cheng($hah){ ; } var_dump(array_map('cheng', ... 
- JS的slice、substring、substr字符串截取
			JS中截取一个字符串的三种方法:字符串.slice(开始索引,结束索引)字符串.substring(开始索引,结束索引)字符串.substr(开始索引,截取的长度) 如果需要截取到该字符串的最后,可以 ... 
- LeetCode 104. 二叉树的最大深度(Maximum Depth of Binary Tree)
			104. 二叉树的最大深度 104. Maximum Depth of Binary Tree 题目描述 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说 ... 
- Echarts 不能百分比显示或显示有问题
			1,设折线图宽为100%(如:容器div的class=“RiBarBot”宽为880px),刚初始化时隐藏折线图(或后期刷新.隐藏与显示折线图时),当点击显示折线图时,获取到的宽只有100px,并不是 ... 
- linux tar包追加问题
			只能已归档的文件才能追加文件. 如果tar.gz文件是如此生成:#tar -zcvf test.tar.gz a.txt即tar.gz是压缩(-z)和归档(-c)文件,则无法给它追加文件:若果tar ... 
- SSM基本案例
			1.搭建环境,导入maven依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sour ... 
