【LeetCode】剑指 Offer 62. 圆圈中最后剩下的数字(约瑟夫环问题) p300 -- Java Version

news2024/11/16 21:31:56

题目链接:https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/

1. 题目介绍(62. 圆圈中最后剩下的数字)

0,1,···,n-1 这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4 这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

【测试用例】:
在这里插入图片描述

【条件约束】:
在这里插入图片描述

2. 题解

2.1 环形链表(经典解法)-- O(mn)

时间复杂度 O(mn),空间复杂度 O(n)
在这里插入图片描述

解题思路】:
经典解法:用环形链表模拟圆圈

  • 我们可以创建一个共有 n 个节点的环形链表,然后每次在这个链表中删除第 m 个节点

……
这样做的优点就在于:

  • 循环链表的向下枚举不需要考虑头尾问题,直接node=node.next向下;
  • 循环聊表的删除也不需要考虑头尾问题,直接node.next=node.next.next删除。
    ……
    Note:当链表结构中不存在前驱节点时,且需要删除某一节点,我们尽可能的提前遍历到要删除节点的前一节点,就通过node.next=node.next.next 来实现删除,而不是等遍历到删除节点,再考虑删除的问题,因此此时没有前驱节点,你将很难确定你的前驱节点是谁,除非提前创建临时节点将当前节点的前驱记录了下来。
    ……

……
但使用循环链表仍有很多问题:

  • 比如说,该方法每次删除一个数字都需要 m 步的运算,一旦碰见 m 远大于 n 的情况,就可能存在在环形链表中重复遍历很多遍的情况,极大地影响了时间复杂度。

……
实现策略】:

  1. 创建头节点 head,并为其赋值为0;
  2. 创建一个链表 team,通过 for 循环对链表进行初始化;
  3. 让链表的尾节点的后继指向头节点,使链表形成环;
  4. 定义索引变量 index,用来指代当前走了多少步,如果走到了m-1步,就开始删除 m步 所处位置的节点;
  5. 删除结束后,返回剩下节点的值。
class Solution {
    // 定义链表结构
    public class ListNode {
        int val;
        ListNode next;
        ListNode(int x) { val = x; }
    }
    // Solution1:环形链表
    public int lastRemaining(int n, int m) {
        if(m == 1) return n-1;  // 一次一个直接返回最后一个即可
        ListNode head = new ListNode(0);
        ListNode team = head;  // 创建一个链表
        for(int i = 1; i < n; i++)
        {
            team.next = new ListNode(i);
            team = team.next;
        }
        team.next = head;  //使形成环
        int index = 1;  //从1开始计数
        while (head.next != head) {  // 当剩余节点不止一个的时候
            // 如果index = m-1 那就说明下个节点(m)该删除了
            // 因为如果遍历到要删除的节点再删除, 此时由于没有前驱节点,我们无法确定当前节点的上一节点是谁?
            // 一般的办法是定义一个临时遍历pre, 提前存储当前节点的上一节点
            // 但此处直接提前判断, 在要删除的上一节点就执行删除操作,即: 将要删除节点的前驱的后继指向要删除节点的后继
            if(index == m-1)
            {
                head.next = head.next.next;
                // 删除之后, 让index归位, 方便后面重新计算
                index = 1;
            }
            else {
                index++;
            }
            head = head.next;
        }
        return head.val;
    }
}

在这里插入图片描述

2.2 模拟链表 + 求余 – O(n2) ⭐

时间复杂度O(n2),空间复杂度O(n)
在这里插入图片描述

解题思路】:
环形链表中使用链表直接模拟游戏全过程造成了非常严重的超时,n个数字,数到第m个出列,m如果非常大,远大于n,那么将产生很多次重复的转圈。
那么在本题解中,就要来解决这个重复转圈的问题:

  • 首先,很多时候我们完全不需要手动去写一个链表结构,而是可以通过ArrayListLinkedList去模拟一个链表;如果使用LinkedList其底层也是链表,使用ArrayList的话其底层数据结构是数组,此处,我们选择了ArrayList来实现链表的模拟;
  • 其次,由上图我们可以推理出一个公式,index=(index+m-1)%(list.size()),根据此公式,我们可以直接确定下一次要删除的元素的具体位置,从而避开重复的转圈遍历。
    ……
    Note:关于删除元素的位置公式,不理解的可以根据上图,自己走一遍流程。在本题中,数字和下标都是从 0 开始起算,所以第 m 步 走到的是 列表中第 m-1 个元素 (m < n 的情况下);而当我们每次找到并删除一个元素时,由于该元素已被删除,它的下标就自动被下一元素所继承,那还是相当于我们只需要走 m-1 步就到了下一个需要删除的元素的位置;同时,我们结合环形链表的特质,通过 位置 与 列表长度 的求余,就可以去掉多余的重复循环,直接找到 要删除元素在列表中的位置。
    ……

……
实现策略】:

  1. 创建列表 list,用来模拟链表;
  2. 初始化列表,将 0 ~ n-1的元素全部加入到列表中;
  3. 循环根据位置公式 idx = (idx+m-1) % list.size() 删除元素,直至列表中剩下最后一个元素;
  4. 最后返回结果。
class Solution {
    // Solution2:模拟链表
    public int lastRemaining(int n, int m) {
        if(m == 1) return n-1; // 一次一个直接返回最后一个即可
        List<Integer> list = new ArrayList<>(); // 创建列表,用来模拟链表
        for (int i = 0; i < n; i++) { // 初始化列表
            list.add(i);
        }
        int idx = 0;
        while (list.size() > 1) { // 循环删除元素,直至剩下最后一个
            idx = (idx+m-1) % list.size(); // 根据公式,我们可以找到每次要删除的元素的位置
            list.remove(idx); 
        }

        return list.get(0);
    }
}

在这里插入图片描述

2.3 数学分析 – O(n)

时间复杂度O(n),空间复杂度O(1)
在这里插入图片描述

解题思路】:
说实话数学题解法,确实又快又好,但难的是怎么推出来,如果碰到其它问题,且之前没有接触过,一般人很难在很短的时间内就能得到正确的推理结果,所以这种数学解法看看,锻炼锻炼思维就好,不要求掌握。
……
推理公式:f(n,m) 指n个人,报第m个编号出列最终编号
在这里插入图片描述
以 n = 10,m = 9 为例:最后结果记为 f(10,3)
在这里插入图片描述
那么其转化过程就为:

  • f(10,3)=(f(9,3)+3)%10
  • f(9,3)=(f(8,3)+3)%9
    ……
  • f(2,3)=(f(1,3)+3)%2
  • f(1,3)=0

……
实现策略】:

  • 根据公式即可轻松写出代码;
class Solution {
    // Solution3:数学分析
    public int lastRemaining(int n, int m) {
        int value=0;
            for(int i=1;i<=n;i++)
            {
                value=(value+m)%i;
            }
            return  value;
    }
}

在这里插入图片描述

3. 参考资料

[1] 圆圈中最后剩下的数字(图解三种方法) – bigsai,该题解在循环链表这一方面讲的很清楚.
[2] Java解决约瑟夫环问题,告诉你为什么模拟会超时!-- Sweetiee🍬的小号,对数学分析题解进行了比较清晰的描述,值得参考.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/452258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工标注或成过去式?SSA语义分割框架、SSA-engine自动类别标注引擎,大幅提升细粒度语义标注效率

推荐语 4月5日&#xff0c;Meta发布 Segment Anything 模型和 SA-1B 数据集&#xff0c;引发CV届“地震”&#xff0c;其凭借一己之力&#xff0c;成功改写了物体检测、数据标注、图像分割等任务的游戏规则。 复旦大学ZVG实验室团队基于此最新开源了SSA语义分割框架和SSA-engin…

javaEE初阶 — Servlet API 详解

文章目录 HttpServlet1 Servlet 的生命周期2 代码示例3 使用 postman 构造请求4 使用 ajax 构造请求 HttpServletRequest1 代码示例 前端如何给后端传参1 通过 GET 里的 query string 传参2 通过 POST 借助 form 表单传参3 通过 json 格式传参 HttpServletResponse1 代码示例1.…

ChatGPT会取代RPA?ta自己可不是这么说的!

先说一个AI热知识&#xff1a;ChatGPT 的推出在科技界引发了一场狂潮。 聊天机器人ChatGPT以及其背后的AI大模型GPT&#xff0c;在2023年引爆全球。GPT 全称为 Generative Pre-trained Transformer&#xff0c;是一种使用人工神经网络的深度学习技术&#xff0c;能够使机器像人…

Transformer and Self-attention

一谈到 NLP&#xff0c;大家都听说过 Transformer&#xff0c; Self-attention 这些词汇&#xff0c;以及 Attension is all you need 这篇论文。 大家可能多多少少看过这类博客&#xff0c;对这些概念有一些了解&#xff0c;什么 QKV呀&#xff0c; encoder&#xff0c; decod…

贪心-刷杂技的牛

题意 农民约翰的 N 头奶牛&#xff08;编号为 1..N&#xff09;计划逃跑并加入马戏团&#xff0c;为此它们决定练习表演杂技。 奶牛们不是非常有创意&#xff0c;只提出了一个杂技表演&#xff1a; 叠罗汉&#xff0c;表演时&#xff0c;奶牛们站在彼此的身上&#xff0c;形成一…

Revit中如何绘制轴线?CAD图纸转轴网操作

一、如何用revit来制作这么一个简单的轴线呢? 01 、新建项目 绘制轴线&#xff0c;首先新建项目建筑样板 02 、轴线快捷键 绘制轴线的快捷键需要牢记&#xff0c;因为经常使用GR 03 、编辑轴线类型 当你画好第一条轴线&#xff0c;需要对轴线类型属性进行调节&#xff0c;一般…

基于vivado(语言Verilog)的FPGA学习(5)——跨时钟处理

基于vivado&#xff08;语言Verilog&#xff09;的FPGA学习&#xff08;5&#xff09;——跨时钟处理 1. 为什么要解决跨时钟处理问题 慢时钟到快时钟一般都不需要处理&#xff0c;关键需要解决从快时钟到慢时钟的问题&#xff0c;因为可能会漏信号或者失真&#xff0c;比如&…

基于HTML5智慧监所三维可视化安防管控系统

前言 物联网技术的发展使云计算技术得到了迅猛的发展及广泛的应用&#xff0c;智能体系的创建已经成为监狱发展的必然趋势。 智慧监狱的创建、智能化管理的推行是监狱管理的创新&#xff0c;也是监狱整体工作水平提升的具体体现。 建设背景 近年来&#xff0c;司法部不断加大…

jumpserver设置密码强度

1、点击系统设置 – 点击安全设置 2、设置密码强弱规则

【SVN】window SVN安装使用教程(服务器4.3.4版本/客户端1.11.0版本)

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

为什么建企业网站对企业来说非常重要?

随着互联网的飞速发展&#xff0c;建企业网站已经成为了企业重要的一部分。企业网站是企业与外界沟通的重要渠道&#xff0c;对于企业的品牌形象、市场推广和销售业绩都有着不可替代的作用。本文将从以下几个方面&#xff0c;阐述为什么建企业网站对企业来说非常重要&#xff0…

Spring5学习总结(五)Spring5的新特性Log4j2@Nullable注解支持函数式风格支持JUnit5

Spring5学习总结&#xff08;五&#xff09;Spring5的新特性/Log4j2/Nullable注解/支持函数式风格/支持JUnit5 整个 Spring5 框架的代码基于 Java8&#xff0c;运行时兼容 JDK9&#xff0c;许多不建议使用的类和方法在代码库中删除 一、支持整合Log4j2 Spring 5.0 框架自带了…

【Java笔试强训】day26编程题

目录 编程题快到碗里来跳台阶问题 编程题 快到碗里来 import java.math.BigDecimal; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);while (sc.hasNext()) {BigDecimal n sc.nextBigDecimal();B…

【leetcode速通java版】04——哈希表

前 言 &#x1f349; 作者简介&#xff1a;半旧518&#xff0c;长跑型选手&#xff0c;立志坚持写10年博客&#xff0c;专注于java后端 ☕专栏简介&#xff1a;代码随想录leetcode速通训练营java版本 &#x1f330; 文章简介&#xff1a;哈希表理论&#xff0c;leetcodeT242,T3…

jekyll+GithubPage搭建一个免费的个人网站

文章目录 Jekyll环境搭建windows安装RUBY、gem、Jekyll用Jekyll搭建本地博客 用jekyll模板搭建githubpage Jekyll环境搭建 windows安装RUBY、gem、Jekyll 安装ruby RUBY安装包下载地址&#xff1a;https://rubyinstaller.org/downloads/&#xff0c;一路默认选项next即可。 最…

热闻丨ChatGPT会替代你我吗?让它写了封情书后,我得到答案

ChatGPT毕竟不是人 2023年的科技圈儿被ChatGPT占据&#xff0c;上线仅仅两个月&#xff0c;活跃用户就突破一亿。上知天文下知地理&#xff0c;ChatGPT以它的强大功能让许多人生出疑问&#xff1a;ChatGPT会替代你我吗&#xff1f; 记者挑选了一些尖锐问题进行询问&#xff0…

【碳达峰碳中和】高校用电智慧监管平台的构建

摘 要&#xff1a;介绍了当前高校用电存在的问题&#xff0c;进行了原因分析&#xff0c;由此提出建立高校用电智慧监管平台。对高校用电智慧监管平台的构架进行设计&#xff0c;运用物联网技术&#xff0c;实现各回路实时自主控制&#xff0c;并细化管理权限&#xff0c;实现…

【5天打卡】学习Lodash的第一天——初体验

大家好&#xff0c;最近&#xff0c;我在学习Lodash这个工具库。Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。一款优秀的 JavaScript 工具库&#xff0c;里面包含了大量的工具函数。适用于常见浏览器以及 Node.js 等。 所以我们一起来学习Lodash&#xff0c…

7. 堆的简单学习

7. 堆 7.1 堆的定义 堆是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常可以被看做是一棵完全二叉树的数组实现。 堆的特性&#xff1a; 它是完全二叉树&#xff0c;除了树的最后一层结点不需要是满的&#xff0c;其它的每一层从左到右都是满的&#xff0c;如果最…

持续集成 在 Linux 上搭建 Jenkins,自动构建接口测试

本篇把从 0 开始搭建 Jenkins 的过程分享给大家&#xff0c;希望对小伙伴们有所帮助。 文章目录 在 Linux 上安装 Jenkins 在 Linux 上安装 Git 在 Linux 上安装 Python 在 Linux 上安装 Allure 配置 Jenkins jenkins 赋能 - 使用邮箱发送测试报告 jenkins 赋能 - 优化测试报告…