笔者投的是嵌入式软件岗,发现手撕代码难度上比软件开发岗是要简单一些的,基本都是leetcode的medeium和easy的水平,基本难的算法不会考,集中在字符串处理和链表,现在把一些常见的链表题做一下。(以下题目均用c++,在类函数里实现)


1.leetcode 21 合并两个有序链表

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

这个题有两种算法,一种是常规算法,一种是递归算法,后者写出来感觉牛逼一点,但是容易出错。

方法一:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode *dummy=new ListNode(0);//虚拟头结点不动ListNode *cur=dummy;//这个结点是变化的if(l1==nullptr)return l2;if(l2==nullptr)return l1;while(l1!=nullptr&&l2!=nullptr){if(l1->val<l2->val){cur->next=l1;l1=l1->next;}else{cur->next=l2;l2=l2->next;}cur=cur->next;}if(l1!=nullptr)cur->next=l1;elsecur->next=l2;  return dummy->next;}
};

方法2:递归算法

终止条件:当两个链表都为空时,表示我们对链表已合并完成。
如何递归:判断 l1 和 l2 头结点哪个更小,然后较小结点的 next 指针指向其余结点的合并结果。(调用递归)

class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(l1==nullptr)return l2;if(l2==nullptr)return l1;if(l1->val<=l2->val){l1->next=mergeTwoLists(l1->next,l2);//较小结点的next指向其余结点return l1;}else{l2->next=mergeTwoLists(l1,l2->next);return l2;}}
};

2、leetcode 23 合并k个升序链表

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

提示:优先级队列(二叉堆) 这种数据结构,把链表节点放入一个最小堆,就可以每次获得 k 个节点中的最小节点

首先搞一个笨方法,两两合并,借助上边的代码。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode *dummy=new ListNode(0);//虚拟头结点不动ListNode *cur=dummy;//这个结点是变化的if(l1==nullptr)return l2;if(l2==nullptr)return l1;while(l1!=nullptr&&l2!=nullptr){if(l1->val<l2->val){cur->next=l1;l1=l1->next;}else{cur->next=l2;l2=l2->next;}cur=cur->next;}if(l1!=nullptr)cur->next=l1;elsecur->next=l2;  return dummy->next;}ListNode* mergeKLists(vector<ListNode*>& lists) {if(lists.size()==0)return nullptr;ListNode* head = lists[0];for (int i = 1; i < lists.size(); ++i) {head = mergeTwoLists(head, lists[i]);}return head;}
};

就是循环一遍,这个方法太蠢了,要搞一个优先级队列来解决这些问题。初始化,我投进去k个有序列表的头结点,优先级判断一遍,取最小的接到dummy上,每投一个把这个结点的下一个结点放入优先级队列,得到新理论的最小接到dummy上,知道当前结点的下一个结点不存在。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/struct cmp{bool operator()(const ListNode *a,const ListNode *b){return a->val>b->val; //这里从大到小,队列的头是最大的,队列的尾是最小的,取走一个b,b->next补充}};
class Solution {
public:ListNode* mergeKLists(vector<ListNode*>& lists) {if(lists.size()==0) return nullptr;priority_queue<ListNode*,vector<ListNode*>,cmp> pq;for(auto list:lists){if(list) pq.push(list);//初始化,先把头入队,现在自动排序了}ListNode *dummy=new ListNode(0);ListNode *cur=dummy;while(!pq.empty()){cur->next=pq.top();pq.pop();cur=cur->next;if(cur->next!=nullptr){pq.push(cur->next);}}return dummy->next;}
};

141、环形链表(快慢指针,注意边界条件,fast->next->next已经运行一次了,fast->next就是下一个结点,结合循环理解一下,肯定是快指针先到边界)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {if(head==nullptr) //注意:结点为空判断一下return false;ListNode *fast=head;ListNode *slow=head;while(fast&&fast->next)//注意判断条件,一定是fast先碰到尾部{slow=slow->next;fast=fast->next->next;if(slow==fast)return true;}return false;}
};

142、环形链表2 这个题主要是找到环之后找环的起点,和一个数学公式有关,这里当环相遇的时候,把其中一个结点放在环的起始点,然后每次前进一步,再次相遇,就找到了起点。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {ListNode *fast=head;ListNode *slow=head;while(fast&&fast->next)//注意判断条件,一定是fast先碰到尾部{slow=slow->next;fast=fast->next->next;if(slow==fast){ListNode *tmp1=slow;while(tmp1!=head){tmp1=tmp1->next;head=head->next;}    return head;}}return nullptr;//注意,没找到返回空}
};

876、链表的中间结点

思路:快慢指针,当fasy走道链表末尾时,slow就指向了终点。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* middleNode(ListNode* head) {ListNode *fast=head;ListNode *slow=head;if(head==nullptr)return nullptr;while(fast!=nullptr&&fast->next!=nullptr){slow=slow->next;fast=fast->next->next;//快指针跳出循环时,慢指针到终点}return slow;}
};

160、相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

思路:解决这个问题的关键是,通过某些方式,让 p1 和 p2 能够同时到达相交节点 c1

我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。

如果这样进行拼接,就可以让 p1 和 p2 同时进入公共部分,也就是同时到达相交节点 c1:(这个思路秒啊)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode *p1=headA;ListNode *p2=headB;while(p1!=p2){if(p1==nullptr)p1=headB;//直接让它等于另一个的头结点elsep1=p1->next;if(p2==nullptr)p2=headA;elsep2=p2->next;}return p1;}
};

19、删除链表的第N个结点。

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

最好一次遍历实现

首先,我们先让一个指针 p1 指向链表的头节点 head,然后走 k 步:

现在的 p1,只要再走 n - k 步,就能走到链表末尾的空指针

用一个指针 p2 指向链表头节点 head,正好走n-k步就可以了。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* findFromEnd(ListNode *head,int n){ListNode *p1=head;ListNode *p2=head;for(int i=0;i<n;++i){p1=p1->next;}while(p1!=nullptr){p2=p2->next;p1=p1->next;}return p2;}ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode *dummy=new ListNode(0);dummy->next=head;//虚拟节点,防止只有一个节点,删了之后就没有了ListNode *tmp=findFromEnd(dummy,n+1);//这里是虚拟节点,防止tmp->next->next不存在,找到倒数的n+1个,然后删去tmp->next=tmp->next->next;return dummy->next;}
};

注意细节,当出现p->next->next时,一定想一想p->next不能时nullptr。

接下来会有一个链表专题练习,练个20道。

应对嵌入式校招面试手撕之——链表相关推荐

  1. 2023华为OD面试手撕代码经验分享

    我们先来看下这个同学的面试经历吧,非常有借鉴的意义. [22届考研渣渣的od求职之旅,推荐一下两个人,德科hr和牛客的老哥] "*********",hr给了机会吧,一开始我都没想 ...

  2. 二分法查找平方和_面试手撕系列:二分法

    最近春招开始了,面试面着面着一言不合就开始手撕代码手撕就手撕,接下来我打算写几个专题讲讲面试中手撕的常见题目 这些都是LeetCode上有的题目 手撕无非就是 树.链表.二分.字符串这些常用的数据结构 ...

  3. 蛇形打印数组(某宝典公司面试手撕代码题)

    背景杂谈 不知道为什么,可能脑袋一下放空了,一不小心就想到了大约2年前,在某个知名的宝典公司面试中,遇到了一道手撕代码题,和多年前的google的那道螺旋遍历数据有异曲同工之妙.现脑洞大开,想写下与大 ...

  4. 前端date format_前端面试-手撕代码篇

    前言 在前端面试有一个非常重要的环节,也是面试者最担心的一个环节.对"手撕代码"的考察需要面试者平时总结和积累(临时抱佛脚是不好使的),在这里笔者就自己如何攻破"手撕代码 ...

  5. 详解面试手撕过的那些排序算法

    前言 只要去大厂面试,必定有一轮算法面试,而这一轮往往是阻碍程序员面试成功的关键.一个程序员的算法基本功是否扎实能够体现出自身的开发能力,下面我尽可能的把常用的排序算法讲清楚. 排序简介 排序(Sor ...

  6. FPGA秋招面试手撕代码20+

    目录 前言 1.序列检测器 (1)三段式状态机实现方式 (2)移位寄存器实现方式 2.序列生成器 (1)移位寄存器方式实现 (2)计数器方式实现 (3)三段式状态机方式实现 3.分频 (1)偶数分频 ...

  7. 【数据结构】手撕单链表

    希望通过博客和大家相互交流,相互学习,如有错误,请评论区指正 文章目录 一.什么是链表 二.手撕链表 属性定义 结点对象 构造方法 链表对象 构造方法 链表的实现 头插 尾插 得到单链表的长度 任意位 ...

  8. C/C++笔试面试手撕代码注意事项

    C/C++笔试和面试过程中难免会要手撕代码,那么手撕代码,面试官或者看试卷的人一般会看哪些点呢?我列举了一些我认为的点(码农适用): 算法思想是否正确 代码逻辑是否清晰明了 代码风格是否美观简洁 注释 ...

  9. 华为面试手撕代码 leetcode 上重点题 附C++解法

    剑指18 删除链表的节点 ListNode* deleteNode(ListNode* head, int val) {if(!head) return head;if(head->val == ...

最新文章

  1. 2019-2020中国趋势报告,203页PPT解读16大机会
  2. APP元素事件操作API
  3. 互联网1分钟 |1113
  4. 打印完全二叉树java_java 完全二叉树的构建与四种遍历方法示例
  5. Shell编程(逻辑判断、文件目录属性判断、if特殊用法、case判断)
  6. 小波变换——哈尔小波,Haar
  7. Swift 模式匹配
  8. centos长ping输出日志的脚本
  9. PR快闪模板 高端黑白超级快闪图文展示开场PR视频模板
  10. 老毛桃发帖子 去广告
  11. 鸟枪换炮,利用python3对球员做大数据降维(因子分析得分),为C罗找到合格僚机
  12. 可编程逻辑器件之按键消抖实验
  13. 基于卷积神经网络(CNN)的图像识别 之 火焰识别
  14. 基于2022高考数学全国卷I概率题解题思路初步分析新冠病毒疫苗
  15. PHP 7系列版本(7.0、7.1、7.2、7.3、7.4)新特性
  16. hadoop常用的命令
  17. 跟益达学Solr5之Facet一瞥
  18. 慎入!超详细240页PPT!史上最强大的计算机网络导论!
  19. 专升本C语言试题分析(四)
  20. 普通话测试第四题评分标准_2017年普通话水平测试评分细则「详细版」

热门文章

  1. vue2理论学习(全套教程,包含vuex、路由等)
  2. python爬虫论文参考文献格式_Python爬虫进阶必备 | XX文学加密分析实例
  3. 怎么打开华硕电脑计算机功能,华硕笔记本小键盘怎么开(笔记本电脑虚拟键盘怎么打开)...
  4. 7.5W10W无线充电解决方案原理图
  5. 路由器被蹭网后,我有被黑的风险吗?
  6. 足浴报钟器哪个好 足浴按摩手法
  7. 【伪大数据】对QQ空间指定好友2017年说说数据的分析
  8. 获取保存在路由器中的ADSL账号和密码
  9. 商务英语有计算机课吗,如何去学商务英语
  10. 绍耕反失败学课程(06)——在正确时间做正确的事情,轻装上阵抛弃负担