【刷题】牛客网 NC132 环形链表的约瑟夫问题

NC132 环形链表的约瑟夫问题

题目描述

根据描述,该题思路类似于报数,第一想法就是构建环形链表。

思路一(链表直通版)

  1. 构建环形链表,赋予对应序号
  2. 进行约瑟夫问题
  3. 报到对应数,删除节点
  4. 一直到只剩一个节点。
c 复制代码
typedef struct listnode{
    int val ;
    struct listnode* next;
} Listnode;

Listnode* buynode(int n ){
	//开辟空间
    Listnode* node = (Listnode*)malloc(sizeof(Listnode));
    //序号赋值
    node->val = n;
    //next 指针赋值
    node->next = NULL;
    //返回节点
    return node;
}
 Listnode* createlist(int n){
    //序号
    int i = 1;
    //创建头尾
    Listnode* phead ,*ptail;
    //先创建第一个节点
    phead = ptail = buynode(i++);
    //循环构建链表
    while(i<=n){
        ptail->next = buynode(i++);
        ptail = ptail->next;
    }
	//将头尾相连,构成循环链表
    ptail->next = phead;
    //返回头节点
    return phead;

 }
int ysf(int n, int m ) {
    // 创建环形链表
    Listnode * head = createlist(n);

    //约瑟夫问题
    //计数
    int count = 1 ;
    //定义 前指针 当前指针
    Listnode* cur ,*prev;
    cur = head;
    prev = NULL;
    while(cur->next != cur){
    	//报到指定数 删除节点
        if(count == m){
        	//前节点 的next指向 当前节点的下一个节点即可删除
            prev->next = cur->next;
            cur = cur->next;
            //报数重置
            count = 1;

        }else{
        	//没有报到指定数 则向后移动。
            prev = cur;
            cur = cur->next;
            count++;
        }
    }
   	//返回序号
    return cur->val;
}

来看运行效果:

运行很顺利

思路二(数组巧解版)

链表的实现虽然简洁,但是遇到较大数据时难免会开辟较大内存空间,所以我们可以使用数组模拟循环链表的过程。

  1. 创建数组,并赋予对应序号值
  2. 开始遍历计数,报到m 将数组前移覆盖删除即可
  3. 一直反复进行到只剩一个元素。
c 复制代码
#define max_num 100001
int ysf(int n, int m ) {
    //初始化数组
    int man[100001];
    for(int i = 0;i<n;i++){
        man[i] = i + 1;
    }
    //计数
    int count = 1;
    //控制下标
    int i =0;
    while(n > 1 ){
        //如果报到对应数
        if(count == m){
        //向前覆盖删除元素
            for(int j = i;j < n-1;j++){
                man[j] = man[j + 1];
            }
            //计数重置
            count = 1;
            //人数减 1
            n--;
            //注意不需要将 i++ 因为删除过程 i 已经指向了后一个元素。
        }
        else{
        //不是对应数 i++ 计数加1
            i++;
            count++;
        }
		//保证不超出 n 范围
        i %= n;

    }
    //返回对应序号
    return man[i];
}

思路三(变态秒杀版)

该思路使用数学公式,进行快速计算
F(N,M)=(F(N-1,M)+M)%N

即我们可以通过目前幸存者逆推其一开始的序号。

而根据刚才的数组思路,可以知道最后的幸存者数组下标是0,所以我们便可以开始逆推。

c 复制代码
int ysf(int n, int m ) {
    //F(N,M)=(F(N-1,M)+M)%N
    //最后幸存者下标为 0
    int p = 0;
    //从人数为2开始逆推,直到人数为n
    for (int i = 2; i <= n; i++) {
    	//依次移动
        p = (p + m) % i;
    }
    //记得将序号加一
    return p + 1;

}

Thanks♪(・ω・)ノ谢谢阅读

下一篇文章见!!!

相关推荐
Jackey_Song_Odd44 分钟前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
乐之者v1 小时前
leetCode43.字符串相乘
java·数据结构·算法
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
️南城丶北离3 小时前
[数据结构]图——C++描述
数据结构··最小生成树·最短路径·aov网络·aoe网络
✿ ༺ ོIT技术༻3 小时前
C++11:新特性&右值引用&移动语义
linux·数据结构·c++
菜鸡中的奋斗鸡→挣扎鸡10 小时前
滑动窗口 + 算法复习
数据结构·算法
axxy200011 小时前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
Uu_05kkq13 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
1nullptr14 小时前
三次翻转实现数组元素的旋转
数据结构
TT哇15 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表