面试常见编程题专题一:链表
2016-03-09 20:20
756 查看
最近在准备找实习,各种刷题。准备把刷过的题以专题的形式做个总结。
先说说链表,链表是一种动态的数据结构,其操作需要通过指针来完成,因此常被用作考察重点。
本文中的单向链表节点定义如下:
struct ListNode
{
int value;
ListNode *next;
ListNode(int x):value(x),next(NULL);
};
1、翻转链表:定义一个函数,输入一个链表的头结点,反转链表并输出头结点。
ListNode *reverselist(ListNode *p)
{
ListNode *pReversedHead = NULL;
ListNode *pNode = p;
ListNode *pPrev = NULL;
ListNode *pNext;
while (pNode != NULL)
{
pNext = pNode->next;
if (pNext == NULL) pReversedHead =pNode;
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
2、从尾到头输出链表(通过递归或者栈来实现,递归的本质就是栈,递归在链表非常长的时候,有可能造成函数调用栈溢出)
void PrintListReversely(ListNode *head){
stack<ListNode *> node;
ListNode *p = head;
while (p!=NULL)
{
node.push(p);
p = p->next;
}
while (!node.empty())
{
p = node.top();
cout<<p->value<<endl;
node.top();
}
}
3、合并两个有序链表
ListNode *merge(ListNode *head1, ListNode *head2){
if (head1 == NULL)
return head2;
else
{
if (head2 == NULL)
return head1;
}
ListNode *p=NULL;
for (; head1 != NULL&&head2 != NULL; p = p->next){
if (head1->value > head2->value){
p = head2;
head2 = head2->next;
}
else{
p = head1;
head1 = head1->next;
}
}
p->next = head1!= NULL ? head1:head2;
/*递归法
if (head1->value > head2->value){
p = head2;
p->next = merge(head1,head2->next);
}
else{
p = head1;
p->next = merge(head1->next,head2);
}
*/
return p;
}
4、找出链表倒数第K个数
ListNode *findKthend(ListNode *head, unsigned int k){
if (head == NULL || k == 0) return NULL;
ListNode *first=head;
ListNode *second=head;
for (int i = 1; i < k; i++){
if (first->next != NULL){
first = first->next;
}
else
{
return
NULL;
}
}
while (first->next!=NULL)
{
first = first->next;
second = second->next;
}
return second;
}
5、删除链表倒数第K个数并返回头结点(思路:找出倒数k+1个节点并使其指向倒数k-1个节点)
ListNode* removeNthFromEnd(ListNode* head, int k) {
ListNode* dummy=new ListNode(-1);
dummy->next=head;
ListNode* record=dummy;
for (int i = 0; i < k; i++){
if (first->next != NULL){
first = first->next;
}
else
{
return
NULL;
}
}
ListNode* result=dummy;
while(record->next){
result=result->next;
record=record->next;
}
result->next=result->next->next;
return dummy->next;
}
6、从无头单链表中删除节点
void deleterandnode(ListNode *p){
if (p== NULL)
return;
ListNode *pNext = p->next;
if (pNext != NULL){
p->value = pNext->value;
p->next = pNext->next;
delete pNext;
}
}
7、添加元素
void addtotail(ListNode **L, int value){
ListNode pNode=ListNode(value);
ListNode *p = &pNode;
if (*L == NULL){
*L = p;
}
else{
ListNode *pnode = *L;
while (pnode->next!=NULL){
pnode = pnode->next;
}
pnode->next = p;
}
}
8、判断是否有环最好的方法是时间复杂度O(n),空间复杂度O(1) 的。设置两个指针,一个快一个慢,快的指针每次走两步,慢的指针每次走一步,如果快指针和慢指针相遇,则说明有环。
bool hascycle(ListNode *head){
i
ListNode *slow = head, *fast = head;
while (fast&&fast->next) //考虑节点个数为奇数和偶数的情况
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast) return true;
}
return false;
}
9、判断一个单链表的环入口,如果没有环,则返回NULL;(下面为我复制的 各位可以自己画个示意图理解下)
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:
ListNode *FindLoopPort(ListNode *head){
if (head == NULL || head->next == NULL){
return NULL;
}
ListNode *slow = head, *fast = head;
while (fast&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast) break;
}
if (fast != slow) return
NULL;
slow = head;
while (slow != fast){
slow = slow->next;
fast = fast->next;
}
return fast;
}
先说说链表,链表是一种动态的数据结构,其操作需要通过指针来完成,因此常被用作考察重点。
本文中的单向链表节点定义如下:
struct ListNode
{
int value;
ListNode *next;
ListNode(int x):value(x),next(NULL);
};
1、翻转链表:定义一个函数,输入一个链表的头结点,反转链表并输出头结点。
ListNode *reverselist(ListNode *p)
{
ListNode *pReversedHead = NULL;
ListNode *pNode = p;
ListNode *pPrev = NULL;
ListNode *pNext;
while (pNode != NULL)
{
pNext = pNode->next;
if (pNext == NULL) pReversedHead =pNode;
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
2、从尾到头输出链表(通过递归或者栈来实现,递归的本质就是栈,递归在链表非常长的时候,有可能造成函数调用栈溢出)
void PrintListReversely(ListNode *head){
stack<ListNode *> node;
ListNode *p = head;
while (p!=NULL)
{
node.push(p);
p = p->next;
}
while (!node.empty())
{
p = node.top();
cout<<p->value<<endl;
node.top();
}
}
3、合并两个有序链表
ListNode *merge(ListNode *head1, ListNode *head2){
if (head1 == NULL)
return head2;
else
{
if (head2 == NULL)
return head1;
}
ListNode *p=NULL;
for (; head1 != NULL&&head2 != NULL; p = p->next){
if (head1->value > head2->value){
p = head2;
head2 = head2->next;
}
else{
p = head1;
head1 = head1->next;
}
}
p->next = head1!= NULL ? head1:head2;
/*递归法
if (head1->value > head2->value){
p = head2;
p->next = merge(head1,head2->next);
}
else{
p = head1;
p->next = merge(head1->next,head2);
}
*/
return p;
}
4、找出链表倒数第K个数
ListNode *findKthend(ListNode *head, unsigned int k){
if (head == NULL || k == 0) return NULL;
ListNode *first=head;
ListNode *second=head;
for (int i = 1; i < k; i++){
if (first->next != NULL){
first = first->next;
}
else
{
return
NULL;
}
}
while (first->next!=NULL)
{
first = first->next;
second = second->next;
}
return second;
}
5、删除链表倒数第K个数并返回头结点(思路:找出倒数k+1个节点并使其指向倒数k-1个节点)
ListNode* removeNthFromEnd(ListNode* head, int k) {
ListNode* dummy=new ListNode(-1);
dummy->next=head;
ListNode* record=dummy;
for (int i = 0; i < k; i++){
if (first->next != NULL){
first = first->next;
}
else
{
return
NULL;
}
}
ListNode* result=dummy;
while(record->next){
result=result->next;
record=record->next;
}
result->next=result->next->next;
return dummy->next;
}
6、从无头单链表中删除节点
void deleterandnode(ListNode *p){
if (p== NULL)
return;
ListNode *pNext = p->next;
if (pNext != NULL){
p->value = pNext->value;
p->next = pNext->next;
delete pNext;
}
}
7、添加元素
void addtotail(ListNode **L, int value){
ListNode pNode=ListNode(value);
ListNode *p = &pNode;
if (*L == NULL){
*L = p;
}
else{
ListNode *pnode = *L;
while (pnode->next!=NULL){
pnode = pnode->next;
}
pnode->next = p;
}
}
8、判断是否有环最好的方法是时间复杂度O(n),空间复杂度O(1) 的。设置两个指针,一个快一个慢,快的指针每次走两步,慢的指针每次走一步,如果快指针和慢指针相遇,则说明有环。
bool hascycle(ListNode *head){
i
ListNode *slow = head, *fast = head;
while (fast&&fast->next) //考虑节点个数为奇数和偶数的情况
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast) return true;
}
return false;
}
9、判断一个单链表的环入口,如果没有环,则返回NULL;(下面为我复制的 各位可以自己画个示意图理解下)
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:
ListNode *FindLoopPort(ListNode *head){
if (head == NULL || head->next == NULL){
return NULL;
}
ListNode *slow = head, *fast = head;
while (fast&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast) break;
}
if (fast != slow) return
NULL;
slow = head;
while (slow != fast){
slow = slow->next;
fast = fast->next;
}
return fast;
}
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- [C/C++]反转链表
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- 只有程序员看的懂的面试圣经|如何拿下编程面试
- 下一次技术面试时要问的 3 个重要问题
- C#实现基于链表的内存记事本实例
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- PHP程序员面试 切忌急功近利(更需要注重以后的发展)
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结