每日两题 T10
算法
LeetCode T面试题62. 圆圈中最后剩下的数字[1]
描述
0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例1
输入: n = 5, m = 3
输出: 3
示例2
输入: n = 10, m = 17
输出: 2
限制
•1 <= n <= 10^5
•1 <= m <= 10^6
分析
著名约瑟夫环问题,可以使用递归实现,但是有存在堆栈溢出问题。分析规律可以使用循环解决。
我们以 n=5, m=3
为例
很明显我们每次删除的是第 mm 个数字,我都标红了。
第一轮是 [0, 1, 2, 3, 4]
,所以是 [0, 1, 2, 3, 4]
这个数组的多个复制。这一轮 2
删除了。
第二轮开始时,从 3
开始,所以是 [3, 4, 0, 1]
这个数组的多个复制。这一轮 0
删除了。
第三轮开始时,从 1
开始,所以是 [1, 3, 4]
这个数组的多个复制。这一轮 4
删除了。
第四轮开始时,还是从 1
开始,所以是 [1, 3]
这个数组的多个复制。这一轮 1
删除了。
最后剩下的数字是 3
。
图中的绿色的线指的是新的一轮的开头是怎么指定的,每次都是固定地向前移位 m
个位置。
然后我们从最后剩下的 3
倒着看,我们可以反向推出这个数字在之前每个轮次的位置。
最后剩下的 3
的下标是 0
。
第四轮反推,补上 m
个位置,然后模上当时的数组大小 2
,位置是 (0 + 3) % 2 = 1
。
第三轮反推,补上 m
个位置,然后模上当时的数组大小 3
,位置是 (1 + 3) % 3 = 1
。
第二轮反推,补上 m
个位置,然后模上当时的数组大小 4
,位置是 (1 + 3) % 4 = 0
。
第三轮反推,补上 m
个位置,然后模上当时的数组大小 5
,位置是 (0 + 3) % 5 = 3
。
所以最终剩下的数字的下标就是 3
。因为数组是从 0
开始的,所以最终的答案就是 3
。
总结一下反推的过程,就是 (当前index + m) % 上一轮剩余数字的个数
。
复杂度分析
•时间复杂度:O(n)O(n),需要求解的函数值有n
个。•空间复杂度:O(1)O(1),只使用常数个变量。
代码
/**
* @param {number} n
* @param {number} m
* @return {number}
*/
var lastRemaining = function (n, m) {
let res = 0;
for (let i = 2; i != n + 1; ++i)
res = (m + res) % i;
return res;
}
前端
要求设计 LazyMan 类,实现以下功能
LazyMan('Tony');
// Hi I am Tony
LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
分析
这是一个很典型的职责链调用问题,我们使用过 jQuery
应该不会陌生链式调用,但是我们发现现在功能中添加了异步操作,我们可以将需要调用的内容存入队列,然后逐步调用。
代码
class LazyManClass {
constructor(name) {
this.name = name
this.queue = []
console.log(`Hi I am ${name}`)
setTimeout(() => {
this.next()
},0)
}
sleepFirst(time) {
const fn = () => {
setTimeout(() => {
console.log(`等待了${time}秒...`)
this.next()
}, time)
}
this.queue.unshift(fn)
return this
}
sleep(time) {
const fn = () => {
setTimeout(() => {
console.log(`等待了${time}秒...`)
this.next()
},time)
}
this.queue.push(fn)
return this
}
eat(food) {
const fn = () => {
console.log(`I am eating ${food}`)
this.next()
}
this.queue.push(fn)
return this
}
next() {
const fn = this.queue.shift()
fn && fn()
}
}
function LazyMan(name) {
return new LazyManClass(name)
}
References
[1]
面试题62. 圆圈中最后剩下的数字: https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
- JavaScript图片库
- SMB共享之SCF文件攻击解析
- JavaScript之arguements对象学习
- 让我们一起写出更有效的CSharp代码吧,少年们!
- SQL学习之计算字段的用法与解析
- JavaScript之JS的执行环境和作用域
- GOF设计模式快速学习
- JavaScript之面向对象学习一
- JavaScript之JS实现动画效果
- 深入入门系列--Data Structure--04树
- SQL学习之高级联结(自联结、自然联结、外联接)
- ExtJs学习笔记(21)-使用XTemplate结合WCF显示数据
- JavaScript之面向对象的概念,对象属性和对象属性的特性简介
- 快速入门系列--WebAPI--04在老版本MVC4下的调整
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 关于Cookie和Session
- 微信小程序实战开发一:在小程序中使用useExtendedLib方法引入官方UI
- python 自动化测试(4):日志类封装
- 微信小程序实战开发三:小程序之全局配置APP.JSON之底部菜单栏tabBar
- python 自动化测试(5):页面基类封装
- 微信小程序实战开发四:小程序获取用户信息流程及信息存储方式解析
- python 自动化测试(6):jar包调用
- 微信小程序实战开发五:使用自定义组件配置一个通用的图片轮播组件。
- 亿级流量系统如何玩转 JVM
- 微信小程序实战开发六:使用weui-flex创建一个可自由配置的布局组件。
- JDBCJava连接MySql数据库
- Python中的集合
- Centos7下误删python2和yum的解决办法
- Java正则表达式匹配日期及基本使用
- VM虚拟机中linux centOS 联网单网卡配置教程