链表类面试题型之一——约瑟夫环
在笔试面试中,链表类是经常重点考的题型。本系列是本人为了准备笔试与面试,综合各类书与博客,整理所得。
希望在此过程中,希望可以深刻理解各种题型,督促自己的学习进步,并且分享给大家。如有错误,非常希望得到指点,不甚感激。
题目描述:
有一个数组a[N]顺序存放0~N-1,要求每隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。以8个数(N=7)为例:{0,1,2,3,4,5,6,7},0->1->2(删除)->3->4->5(删除)->6->7->0(删除),如此循环直到最后一个数被删除。
输入描述:
每组数据为一行一个整数n(小于等于1000),为数组成员数,如果大于1000,则对a[999]进行计算。
输出描述:
一行输出最后一个被删掉的数的原始下标位置。
本题也是来自于华为的一条上机题, 也是一个很经典的问题:约瑟夫环问题,相比大家都不陌生。对于约瑟夫环问题,解法也是有很多,比如数组,链表,队列或是直接推导出数学公式。本文,采用了比较普遍的循环链表。对于循环链表,此问题也是最为典型的应用。
实现的步骤也是比较清晰:建立链表,按照步数循环删除结点,直到仅剩一个结点时,为要找的结果。需注意的是在建立链表或是插入,删除操作时,均应对第一个结点特别注意。
实现代码如下:
struct node{
int data;
node* next;
};
int del_n(int n, int interval){
node *head, *curr, *temp;
//生成头结点
head = (node*)malloc(sizeof(node));
head->data = 0;
head->next = NULL;
curr = head;
//读入n个数
for(int i=0; i<n; i++){
temp = (node*)malloc(sizeof(node));
head->data++;
temp->data = i;
if(curr == head){//第一个结点
temp->next = temp;
}else{
temp->next = curr->next;
}
curr->next = temp;
curr = temp;
}
//删除结点
temp = head->next;
while(head->data > 1){
for(int i=0; i<interval; i++){
curr = temp;
temp = temp->next;
}
curr->next = temp->next;
temp = temp->next;
head->data--;
count++;
}
return temp->data;
}
对于使用队列的方式,实现约瑟夫环问题,将在下文实现。
不足之处,敬请谅解,欢迎交流。
对于题目与解法的来源,本人尽量给出出处,尊重原创,方便大家寻找。