嵌入式软件常用面试题汇总之 C/C++ 语言相关(4)
C/C++之常考链表相关基础编程题汇总
嵌入式的笔试中编程题大部分会是基础的链表操作题,以下挑几道当时做过比较重点经典的,掌握了基本就能通关,参考的解法都是几年前自己做的了,也欢迎各位优化指正!
1.环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。 示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。 提示:
|
解法参考:
/**
* 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 == NULL || head->next == NULL )
{
return false;
}
ListNode *fast = head;
ListNode *slow = head;
//此处有一个细节,判断(fast->next->next) != NULL之前需要对fast->next进行判断,不然会报错
while(fast->next != NULL && (fast->next->next) != NULL )
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
return true;
}
}
return false;
}
};
2.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4] 示例 2: 输入:l1 = [], l2 = [] 输出:[] 示例 3: 输入:l1 = [], l2 = [] 输出:[] 提示:
|
解法参考:
/**
* 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* list1, ListNode* list2) {
if(list1==NULL) return list2;
if(list2==NULL) return list1;
if(list1->val < list2->val)
{
list1->next = mergeTwoLists(list1->next,list2);
return list1;
}else
{
list2->next = mergeTwoLists(list1,list2->next);
return list2;
}
}
};
/*方法二:双指针,类似于之前的数组合并 */
// if(list1==NULL) return list2;
// if(list2==NULL) return list1;
// ListNode* result = new ListNode; //注意不能返回局部变量,所以要申请地址
// ListNode* p = result; //借助P来完成遍历的操作
// ListNode* l1 = list1;
// ListNode* l2 = list2;
// while(l1!=NULL && l2!= NULL)
// {
// if(l1->val <= l2->val )
// {
// p->next = l1;
// p = p->next;
// l1 = l1->next;
// }else if(l1->val > l2->val )
// {
// p->next = l2;
// p = p->next;
// l2 = l2->next;
// }
// }
// if(l1 == NULL)
// {
// p->next = l2;
// return result->next;
// }else if(l2 == NULL)
// {
// p->next = l1;
// return result->next;
// }
// return result->next;
/* */
3.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] 示例 2: 输入:head = [1], n = 1 输出:[] 示例 3: 输入:head = [1], n = 1 输出:[] 提示:
|
解法参考:
/*方法:
第一种:用一个哈希表,key值是顺序,遍历一遍链表把结点都顺序存到哈希表里面,最后再直接拿到 n-k+1的那个结点即可
第二种:不用哈希表,但是要遍历两次链表,第一计算总长度,第二次去取对应位置的值
第三种:快慢指针,快指针先走k-1个节点,然后和慢指针一起每次走一步,当快指针到尾部时慢指针即为所要找的结点
然后注意这道题是删掉这个结点,所以变通一下
*/
/**
* 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* removeNthFromEnd(ListNode* head, int n)
{
if(head->next == NULL)
{
head = NULL;
return head;
}
ListNode* fast = head;
ListNode* slow = head;
for(int i = 0 ; i < n ; i++)//这里想让slow是要删除的前一个,但是要注意边界
{
fast = fast->next;
}
if(fast == NULL) return head->next;
while(fast->next != NULL)
{
slow = slow->next;
fast = fast->next;
}
//此时slow为要删的前一个
ListNode* pos = slow->next;
slow->next = pos->next;
return head;
}
};
4.两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807. 示例 2: 输入:l1 = [0], l2 = [0] 输出:[0] 示例 3: 输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1] 提示:
|
解法参考(发现以前自己写了一堆if else.....有空再优化看看解法):
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* CreatNode(int data){
struct ListNode* NewNode = (struct ListNode*)malloc(sizeof(struct ListNode));
NewNode->next=NULL;
NewNode->val=data;
return NewNode;
}
void InsertNode(struct ListNode* HeadNode,int data){
struct ListNode* NewNode = CreatNode(data);
struct ListNode* PosNode = HeadNode;
while(PosNode->next!=NULL){
PosNode=PosNode->next;
}
PosNode->next=NewNode;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
int Posflag=0;
char Addflag=0;
int data=0;
struct ListNode* HeadNode = CreatNode(0);
while(1){
if(l1!=NULL&&l2!=NULL){
if(l1->val+l2->val+Addflag<10){
data=l1->val+l2->val+Addflag;
Addflag=0;
l1=l1->next;
l2=l2->next;
InsertNode(HeadNode,data);
}else if(l1->val+l2->val+Addflag>=10){
data=l1->val+l2->val+Addflag-10;
Addflag=1;
l1=l1->next;
l2=l2->next;
InsertNode(HeadNode,data);
}
}else if(l1!=NULL&&l2==NULL){
if(l1->val+Addflag<10){
data=l1->val+Addflag;
Addflag=0;
l1=l1->next;
InsertNode(HeadNode,data);
}else if(l1->val+Addflag>=10){
data=0;
Addflag=1;
l1=l1->next;
InsertNode(HeadNode,data);
}
}else if(l1==NULL&&l2!=NULL){
if(l2->val+Addflag<10){
data=l2->val+Addflag;
Addflag=0;
l2=l2->next;
InsertNode(HeadNode,data);
}else if(l2->val+Addflag>=10){
data=0;
Addflag=1;
l2=l2->next;
InsertNode(HeadNode,data);
}
}else if(l1==NULL&&l2==NULL){
if(Addflag){
InsertNode(HeadNode,1);
} break;
}
}
HeadNode=HeadNode->next;
return HeadNode;
}
5.反转链表
给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2:
输入:head = [1,2] 输出:[2,1] 示例 3: 输入:head = [] 输出:[] 提示:
|
解法参考:
/**
* 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* reverseList(ListNode* head)
{
ListNode* pre=NULL;
ListNode* pos=head;
while(pos!=NULL)
{
ListNode* temp=pos->next;
pos->next = pre;
pre = pos;
pos = temp;
}
return pre; //最后循环完毕时 pos指向空 pre为最后一个结点
}
};
//方法2:
// {
// ListNode* pre=NULL;
// ListNode* pos=head;
// while(pos!=NULL)
// {
// ListNode* temp = pos->next;
// pos->next=pre;
// pre=pos;
// pos=temp;
// }
// return pre;
// }
// if(head == NULL)
// {
// return head;
// }else if (head->next==NULL)
// {
// return head;
// }
// ListNode* pre=head;
// ListNode* pos=head->next;
// if(pos->next==NULL) //若只有两个结点 则直接换个顺序返回
// {
// pre->next=NULL;
// pos->next=pre;
// return pos;
// }
// while(pos!=NULL)
// {
// ListNode* temp=pos->next;
// pos->next = pre;
// pre = pos;
// pos = temp;
// }
// return pre; //最后循环完毕时 pos指向空 pre为最后一个结点
// }
#23届找工作求助阵地##笔试##笔试题##编程##链表题#该专栏是我整理的一些嵌入式软件笔面试常见的题目,在有一定计算机基础上,再过一遍该专栏的内容,对应届生校招来说基本上笔面试就没什么问题了! 有任何疑问可随时与我联系,一起交流一起进步。








查看5道真题和解析

