难度 题目 知识点
03. 返回链表的反序 vector 递归,C++ STL reverse()
* 14. 链表中倒数第k个结点 指针操作
15. 反转链表 头插法,递归
16. 合并两个有序链表 指针操作
*** 25. 复杂链表的复制 深度复制
* 36. 两个链表的第一个公共结点 栈辅助,链表拼接,链表截取
*** 55. 链表中环的入口结点 断链法,快慢指针
* 56. 删除链表中重复的结点 指针操作

03. 返回链表的反序 vector

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

递归或者对正序 vector reverse。

class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> rst;
if(head == NULL)return rst;
rst = printListFromTailToHead(head->next);
rst.emplace_back(head->val);
return rst;
}
}; //----------------------vv---------------------------------
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> rst; ListNode* pNode = head;
while(pNode!=NULL){
rst.emplace_back(pNode->val);
pNode=pNode->next;
} reverse(rst.begin(),rst.end());
return rst;
}
};

14. 链表中倒数第k个结点+

输入一个链表,输出该链表中倒数第k个结点。

这道题去南大面试还被问了,两个指针的思路不错,但是涉及指针的细节很多,容易写崩。。。

/*
首先要判断指针是否为空,以及k是否大于0!!
然后p1移到最后一个为止,不能指到空
*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead == NULL || k==0)
return NULL; ListNode* p1=pListHead;
ListNode* p2=pListHead; for(int i=1;i<k;i++){
if(p1->next==NULL){
return NULL;
}
p1=p1->next;
} while(p1->next != NULL){
p1=p1->next;
p2=p2->next;
} return p2;
}
};

15. 反转链表

用头插法新建了一个链表。当然不新开链表是可以的,似乎正解也是这样。。然后递归也可以但没必要。

16. 合并两个有序链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

/*
A: 考归并操作。
T: 要时刻记得指针所指的结点,不要漏掉!
*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode *newList = new ListNode(0);
ListNode *p1 = pHead1, *p2 = pHead2, *p3 = newList; while(p1 && p2){
if(p1->val <= p2 -> val){
p3->next = p1;
p1 = p1->next;
}else{
p3->next = p2;
p2 = p2->next;
}
p3 = p3->next;
p3->next = NULL;
} if(p1){
p3->next = p1;
}else if(p2){
p3->next = p2;
} return newList->next;
}
};

25. 复杂链表的复制 ++

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空。

方法 1:map关联新节点旧结点

方法 2:妙啊(滑稽

public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead==null) return null;
//1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
RandomListNode p=pHead,newHead=new RandomListNode(0),q;
while(p!=null){
RandomListNode newNode =new RandomListNode(p.label);
newNode.next=p.next;
p.next=newNode;
p=newNode.next;
} //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
p=pHead;
while(p!=null){
if(p.random!=null)
p.next.random=p.random.next;
p=p.next.next;
} //3、拆分链表,将链表拆分为原链表和复制后的链表
p=pHead;
q=newHead;
while(p!=null){
q.next=p.next;
p.next=q.next.next; p=p.next;
q=q.next;
} return newHead.next;
}
}

36. 两个链表的第一个公共结点+

从第一个公共结点开始,都为公共结点,

方法 1:借助辅助栈

我们可以把两个链表的结点依次压入到两个辅助栈中,这样两个链表的尾结点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出继续比较下一个,直到找到最后一个相同的结点。此方法也很直观,时间复杂度为O(m+n),但使用了O(m+n)的空间,相当于用空间换区了时间效率的提升。

方法 2:将两个链表设置成一样长

具体做法是先求出两个链表各自的长度,然后将长的链表的头砍掉,也就是长的链表先走几步,使得剩余的长度与短链表一样长,这样同时向前遍历便可以得到公共结点。时间复杂度为O(m+n),不需要额外空间。

方法 3:将两个链表拼接起来。

将两个链表进行拼接,一个链表1在前链表2在后,另一个链表2在前链表1在后,则合成的两个链表一样长,然后同时遍历两个链表,就可以找到公共结点,时间复杂度同样为O(m+n)。

//方法3
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {
ListNode *p1 = pHead1;
ListNode *p2 = pHead2;
while(p1!=p2){
p1 = (p1==NULL ? pHead2 : p1->next);
p2 = (p2==NULL ? pHead1 : p2->next);
}
return p1;
}
};

55. 链表中环的入口结点+++

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

方法 1:断链法

采用断链法,访问过的节点都断开,最后到达的那个节点一定是循环的入口节点。

public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
if (pHead == null || pHead.next == null) {
return null;
}
ListNode fast = pHead.next;
ListNode slow = pHead;
while (fast != null) {
slow.next = null;
slow = fast;
fast = fast.next;
}
return slow;
}
}

方法 2:快慢指针

利用快慢指针,快指针一次走两步,慢指针一次走一步,具体思路如下:

①判断是否有环:若链表中存在环,快慢指针一定会在环上某一点相遇(因为相对速度为1);

②确定环的起点:

​ 设x为环前面的路程(黑色路程),a为环入口到相遇点的路程(蓝色路程,假设顺时针走), c为环的长度(蓝色+橙色路程)。则有

  • 慢指针走的路程 Sslow = x + m * c + a
  • 快指针走的路程为Sfast = x + n * c + a
  • 2 Sslow = Sfast

​ 可得 x = c - a,即相遇点后环剩余部分的路程。所以,我们可以让一个指针从链表起点开始走,让一个指针从相遇点开始继续往后走,俩指针会在环的起点相遇。

public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead==null || pHead.next == null ||pHead.next.next ==null)
return null; // 判环
ListNode fast= pHead.next.next;
ListNode slow= pHead.next; while (fast!=slow){
if(fast.next!=null && fast.next.next!=null){
fast = fast.next.next;
slow = slow.next;
} else{
return null;
}
} //循环出来的话就是有环,且此时fast==slow,快慢指针在相遇点
fast=pHead;
while (fast!=slow){//将在环的起点相遇
fast=fast.next;
slow=slow.next;
} return slow;
}
}

56. 删除链表中重复的结点+

题目描述:

在一个排序的链表中,存在连续重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。

例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

很容易写错了。

public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
ListNode newHead = new ListNode(-10000000);//增加头节点统一操作
newHead.next=pHead; ListNode pre = newHead, cur; while(pre!=null && pre.next!=null && pre.next.next!=null){
if(pre.next.val==pre.next.next.val){//pre指向重复元素的前一个元素
cur=pre.next;
while(cur.next!=null&&cur.next.val==pre.next.val){
cur=cur.next;
}
pre.next=cur.next;
}
else{// 放在else里是因为刚删完元素后,不能保证pre指针后面两个元素不等,所以pre要保持不动
pre = pre.next;
}
} return newHead.next;
}
}

《剑指offer》链表专题 (牛客10.23)的更多相关文章

  1. 《剑指offer》Q13-18 (牛客10.13)

    目录 Q13 调整数组顺序使奇数位于偶数前 Q14 链表中倒数第k个结点 Q15 反转链表 Q16 合并两个有序链表 Q17 树的子结构 Q18 二叉树的镜像 Q13 调整数组顺序使奇数位于偶数前 输 ...

  2. 《剑指offer》Q01-12 (牛客10.11)

    目录 T1 二维部分有序数组查找 ☆ T2 字符串字符不等长替换 - 从后往前 T3 返回链表的反序 vector T4 重建二叉树 T5 两个栈模拟队列 T6 旋转数组中的最小元素 - 二分或暴力 ...

  3. 《剑指offer》树专题 (牛客10.25)

    考察的知识点主要在于树的数据结构(BST,AVL).遍历方式(前序,中序,后序,层次).遍历算法(DFS,BFS,回溯)以及遍历时借助的数据结构如队列和栈.由于树本身就是一个递归定义的结构,所以在递归 ...

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

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

  5. 《剑指offer》数组专题 (牛客10.22)

    目录 // Q01 二维部分有序数组查找 [善用性质] // Q06 旋转数组中的最小元素 [二分 || 暴力] Q13 调整数组顺序使奇数位于偶数前 / Q19 顺时针打印矩阵 [使用边界变量] / ...

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

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

  7. 剑指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 ...

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

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

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

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

随机推荐

  1. Oracle不足补零函数

    ,') from dual ,') from dual ,') from dual ,') from dual ,') from dual

  2. Sort a list(tuple,dict)

    FROM:https://www.pythoncentral.io/how-to-sort-python-dictionaries-by-key-or-value/ AND https://www.p ...

  3. 洛谷P1330 封锁阳光大学【dfs】

    题目:https://www.luogu.org/problemnew/show/P1330 题意:一个无向边,一个河蟹可以占领一个点,但一个点只能被一个河蟹占领. 占领了一个点之后,这个点所有的边都 ...

  4. 通过德鲁伊druid给系统增加监控

    系统在线上运行了一段时间后,比如一年半载的,我们发现系统可能存在某些问题,比如执行系统变慢了,比如某些spring的bean无法监控各种调用情况. 触发到db的各种执行情况,这个时候,我们就需要一个工 ...

  5. 从入门到精通djang Django

    http://docs.30c.org/djangobook2/ 推荐大家一本书 特别用用  中文版的 哦

  6. Appium自动化测试教程-自学网-monkey简介

    Monkey简介 在Android的官方自动化测试领域有一只非常著名的“猴子”叫Monkey,这只“猴子”一旦启动,就会让被测的Android应用程序像猴子一样活蹦乱跳,到处乱跑.人们常用这只“猴子” ...

  7. 【luogu1325】雷达安装--贪心

    题目描述 描述: 假设海岸线是一条无限延伸的直线.它的一侧是陆地,另一侧是海洋.每一座小岛是在海面上的一个点.雷达必须安装在陆地上(包括海岸线),并且每个雷达都有相同的扫描范围d.你的任务是建立尽量少 ...

  8. 解决python在命令行中运行时导入包失败,出现错误信息 "ModuleNotFoundError: No module named ***"

    转自https://www.cnblogs.com/dreamyu/p/7889959.html https://www.cnblogs.com/lifeofershisui/p/8135702.ht ...

  9. PHP学习之工厂模式

    <?php //工厂模式 interface Doing { function eat(); function sleep(); } class Cat implements Doing { f ...

  10. linux tftp配置 (Ubuntu18.04)

    安装tftp客户端和服务器sudo apt-get install tftp-hpa tftpd-hpa xinetdtftp-hpa是客户端tftpd-hpa是服务器 配置文件 sudo vim / ...