Appearance
全局配置
Appearance
有一个数组:
const arr = [[1,2],3,[4,5,6]];定义一个函数,传入arr后,返回值为一个二维数组:
[[1,3,4],[2,3,4],[1,3,5],[2,3,5],[1,3,6],[2,3,6]]function f(arr) {
// 用于存放最后结果的空数组
var ret = []
// 函数result
function fi(result, i) {
if (i === -1) {
ret.push(result)
} else {
let items = arr[i]
if (!Array.isArray(items)) {
items = [items]
}
items.forEach(item => {
fi([item,...result], i - 1)
});
}
}
fi([], arr.length - 1)
return ret
}
const arr = [[1,2],3,[4,5,6]];
console.log(f(arr))function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}
return arr2;
} else {
return Array.from(arr);
}
}
function f(arr) {
var ret = [];
function fi(result, i) {
if (i === -1) {
ret.push(result);
} else {
var items = arr[i];
if (!Array.isArray(items)) {
items = [items];
}
items.forEach(function (item) {
fi([item].concat(_toConsumableArray(result)), i - 1);
});
}
}
fi([], arr.length - 1);
return ret;
}
var arr = [[1, 2], 3, [4, 5, 6]];
console.log(f(arr));如何提取数组中的字段,然后添加新的字段,获取数据如下:
var data = [
{"id":"1","name":"华为","data":"25u6s8f545d3"},
{"id":"2","name":"小米","data":"cd58de9d3c5d"},
];想获得的数据格式如下:
var data = [
{"id":"1","name":"华为","data":"25u6s8f545d3","mac":"25:u6:s8:f5:45:d3"},
{"id":"2","name":"小米","data":"cd58de9d3c5d","mac":"cd:58:de:9d:3c:5d"},
];var data = [
{ "id": "1", "name": "华为", "data": "25u6s8f545d3" },
{ "id": "2", "name": "小米", "data": "cd58de9d3c5d" },
];
data.forEach(item => {
item.mac = item.data.replace(/\w{2}\B/g, '$&:')
})
console.log(data)打印类似效果:
4444
333
22
1
22
333
4444function f(n) {
for (let i = -n; i <= n; i++) {
if (i === 0 || i === 1) {
continue
}
let k = Math.abs(i)
console.log(k.toString().repeat(k))
}
}
f(4);让字符串"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 每7个字符换行一次
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aavar str='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
var result = str.replace(/(.{7})/g, '$1\n')
console.log(result);请写一段js程序,定义一个列表类List,该类包括两个成员:属性length(表示列表中的元素个数)和方法add(向列表添加元素),其中要求构造函数和add方法的参数为动态参数。
class List{
constructor(...items){
this.items = items
this.length = items.length
}
add(...items) {
this.items.push(...items)
this.length = this.items.length
}
}比如有这样一个对象数组:
let data = [
{
title: '标题一',
tagName: 'h1'
},
{
title: '标题二',
tagName: 'h1'
},
{
title: '标题三',
tagName: 'h2'
},
{
title: '标题四',
tagName: 'h3'
},
{
title: '标题五',
tagName: 'h2'
},
{
title: '标题六',
tagName: 'h1'
},
{
title: '标题七',
tagName: 'h1'
},
{
title: '标题八',
tagName: 'h2'
},
{
title: '标题九',
tagName: 'h3'
},
{
title: '标题十',
tagName: 'h3'
}
]要求根据tagName的优先级,从h1开始排,一直到h6,每个h1后面直到下个h1之前的都是它的children节点,依此类推,比如上面的数据这样处理后就会像下面的格式:
let data = [
{
title: '标题一',
tagName: 'h1'
},
{
title: '标题二',
tagName: 'h1',
children: [
{
title: '标题三',
tagName: 'h2'
children: [
{
title: '标题四',
tagName: 'h3'
}
]
},
{
title: '标题五',
tagName: 'h2'
}
]
},
{
title: '标题六',
tagName: 'h1'
},
{
title: '标题七',
tagName: 'h1',
children: [
{
title: '标题八',
tagName: 'h2',
children: [
{
title: '标题九',
tagName: 'h3'
},
{
title: '标题十',
tagName: 'h3'
}
]
}
]
}
]function collect(arr, i, parent) {
if (i >= arr.length) {
return i
}
let current = arr[i]
if (current.tagName > parent.tagName) {
parent.children.push(current)
} else {
return i
}
i++
let next = arr[i]
if (!next) {
return i
}
if (next.tagName > current.tagName) {
current.children = []
i = collect(arr, i, current)
}
return collect(arr, i, parent)
}
var ret = {
tagName: 'h0',
children: []
}
collect(data, 0, ret)
console.log(ret.children)使用random函数每次随机分配。每次得出的红包值大于 [0.01],小于 [剩余金额-剩余人数*0.01],最后一个人获得剩余全部。
function rp(total, n) {
var remain = total
var ret = []
for (let i = 0; i < n - 1;i++) {
let m = Math.ceil(Math.random() * 100 * (remain - (n - (i + 1)) * 0.01)) / 100
ret.push(m)
remain -= m
}
ret.push(Number(remain.toFixed(2)))
return ret
}简化下面的函数:
function mergeJsonObject(jsonObj1, jsonObj2, jsonObj3, jsonObj4, jsonObj5) {
let resultJsonObject = {};
function jsonObj(jsonObj) {
for (let attr in jsonObj) {
resultJsonObject[attr] = jsonObj[attr];
}
}
jsonObj(jsonObj1);
jsonObj(jsonObj2);
jsonObj(jsonObj3);
jsonObj(jsonObj4);
jsonObj(jsonObj5);
return resultJsonObject;
}function mergeJsonObject(...args) {
let resultJsonObject = {};
function jsonObj(jsonObj) {
for (let attr in jsonObj) {
resultJsonObject[attr] = jsonObj[attr];
}
}
args.forEach(jsonObj)
return resultJsonObject;
}一段字符串如下:
表名1@字段1~表名1@字段2~表名2@字段1~表名2@字段2如何将其合理地处理为json格式,如:
{
表名1:[字段1,字段2],
表名2:[字段1, 字段2]
}var str = '表名1@字段1~表名1@字段2~表名2@字段1~表名2@字段2'
var obj = str.split('~').reduce((state, item) => {
var [tname, fname] = item.split('@')
if (state[tname]) {
state[tname].push(fname)
} else {
state[tname] = [fname]
}
return state
}, {})某个对象:
var prd = {
"id": 1,
"department_id": 42,
"products": [{
"id": 12,
"name": "49da",
"grouped_addons": [{
"addons": [{
"id": "0_0_40",
"name": "rice",
"qty": 0,
"unit_price": "5.00"
},
{
"id": "0_0_41",
"name": "what",
"qty": 1,
"unit_price": "15.00"
}
]
}]
},
{
"id": 12,
"name": "49da",
"grouped_addons": [{
"addons": [{
"id": "0_0_40",
"name": "rice",
"qty": 0,
"unit_price": "5.00"
}, {
"id": "0_0_41",
"name": "what",
"qty": 1,
"unit_price": "15.00"
}]
}]
},
{
"id": 42,
"name": "345dd",
"grouped_addons": [{
"addons": [{
"id": "0_0_42",
"name": "rice",
"qty": 0,
"unit_price": "5.00"
}, {
"id": "0_0_43",
"name": "what",
"qty": 1,
"unit_price": "15.00"
}]
}]
},
{
"id": 48,
"name": "33ffg",
"grouped_addons": [{
"addons": [{
"id": "0_0_44",
"name": "rice",
"qty": 0,
"unit_price": "5.00"
}, {
"id": "0_0_45",
"name": "what",
"qty": 1,
"unit_price": "15.00"
}]
}]
},
{
"id": 48,
"name": "33ffg",
"grouped_addons": [{
"addons": [{
"id": "0_0_44",
"name": "rice",
"qty": 1,
"unit_price": "5.00"
}, {
"id": "0_0_45",
"name": "what",
"qty": 3,
"unit_price": "15.00"
}]
}]
}
]
}想要将prd中的products中id相同的对象中的grouped_addons内id相同的qty相加合并,最终的结果想要如下:
var prd = {
"id": 1,
"department_id": 42,
"products": [{
"id": 12,
"name": "49da",
"grouped_addons": [{
"addons": [{
"id": "0_0_40",
"name": "rice",
"qty": 0,
"unit_price": "5.00"
},
{
"id": "0_0_41",
"name": "what",
"qty": 2,
"unit_price": "15.00"
}
]
}]
},
{
"id": 42,
"name": "345dd",
"grouped_addons": [{
"addons": [{
"id": "0_0_42",
"name": "rice",
"qty": 0,
"unit_price": "5.00"
}, {
"id": "0_0_43",
"name": "what",
"qty": 1,
"unit_price": "15.00"
}]
}]
},
{
"id": 48,
"name": "33ffg",
"grouped_addons": [{
"addons": [{
"id": "0_0_44",
"name": "rice",
"qty": 1,
"unit_price": "5.00"
}, {
"id": "0_0_45",
"name": "what",
"qty": 4,
"unit_price": "15.00"
}]
}]
}
]
}var mp = prd.products.reduce((obj, item) => {
if (!obj[item.id]) {
obj[item.id] = [item]
} else {
obj[item.id].push(item)
}
return obj
}, {})
prd.products = Object.keys(mp).map(id => {
return mp[id].reduce((state, item) => {
item.grouped_addons[0].addons.forEach(addon => {
var item = state.grouped_addons[0].addons.find(a => a.id === addon.id)
item.qty += addon.qty
})
return state
})
})
console.log(prd)写一个叫做 laugh() 的函数,它有一个参数n,表示要返回的 "ha" 的数量。
// ES6
function laugh (n) {
// ES6中`repeat`方法返回一个新字符串,表示将原字符串重复`n`次。参数如果是小数,会被取整。
return 'ha'.repeat(n)
}
// ES5
function laugh (n) {
var result = ''
for (var i = 0; i < n; i++) {
result += 'ha'
}
return result
}从数字 1 循环访问到 20
如果数字可以被 3 整除,则输出 “Julia”
如果可以被 5 整除,则输出 “James”
如果可以同时被 3 和 5 整除,则输出 “JuliaJames”
如果不能被 3 或 5 整除,则输出该数字for (var i = 1; i < 21; i++) {
(function (n) {
test(n);
})(i)
}
function test(num) {
if ((num % 3 === 0) && (num % 5 === 0)) {
console.log("JuliaJames");
}
if (num % 3 === 0) {
console.log("Julia");
}
if(num % 5 === 0) {
console.log("James");
}
console.log(num);假设现在有两个函数function A()和function B(),现在希望创建一个新的函数function C(),新函数的逻辑是将自己接收到的前两个参数传给函数A,剩余所有参数传给函数B,请用原生javascript实现函数C
举例:
如果调用函数C:C(a,b,c,d,e)
相当于调用函数A和函数B:A(a,b)和B(c,d,e)// ES5
function C() {
var args = [].slice.call(arguments)
A.apply(null, args.slice(0, 2))
B.apply(null, args.slice(2))
}
// ES6 展开运算符
function a(v1, v2){
console.log(v1, v2);
}
function b(...v){
console.log(v);
}
function c(...all){
a(all[0], all[1]);
b(...(all.slice(2)));
}
c(1, 2, 3, 4, 5, 6, 7);已知函数 fn 执行需要 3 个参数。请实现函数 partial,调用之后满足如下条件:
1、返回一个函数 result,该函数接受一个参数
2、执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致function partial(fn,str1,str2) {
var result = function(str3) {
return fn.call(null,str1,str2,str3);
}
return result;
}给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式。
这里的遵循指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应模式。示例1:
输入: pattern = "abba", str = "dog cat cat dog"
输出: true示例2:
输入:pattern = "abba", str = "dog cat cat fish"
输出: false说明:
你可以假设 pattern 只包含小写字母, str 包含了由单个空格分隔的小写字母。思路:
用JS ES6的Map结构,将pattern和str作为键值对传入数组,如果Map中存在pattern中的键,则比较Str中值;如果不存在键,则看Str中的值在Map中是否存在。如果键和值都在Map中,则将键值对加入Map中var wordPattern = function(pattern, str) {
let map = new Map();
//将str转为数组
words = str.split(" ");
//遵循指完全匹配,长度不等,直接返回
if(pattern.length !== words.length) return false;
for (let i = 0; i < words.length; i++){
//判断map中是否存在该键,如果存在且值不等,则返回false
if (map.has(pattern[i])){
if (map.get(pattern[i]) !== words[i]) {
return false;
}
} else{
//如果不存在键,但值存在,也返回false
//由于map没有查看值的方法,只能去所有的值然后遍历,不知道这里有没有简便的处理方式
let hasValue = [...map.values()].some(value => value === words[i]);
if (hasValue) {
return false;
}
//键值都不存在,则添加键值对至map中
map.set(pattern[i], words[i]);
}
}
return true;
};给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。
示例1:
输入: s = "anagram", t = "nagaram"
输出: true示例2:
输入: s = "rat", t = "car"
输出: falsevar isAnagram = function(s, t) {
if(s.length != t.length){
return false;
}
let arrs = s.split("").sort();
let arrt = t.split("").sort();
for(let i = 0 ; i < arrs.length; i++){
if(arrs[i] != arrt[i]){
return false;
}
}
return true;
};对数组进行去重操作,只考虑数组中元素为数字或字符串,返回一个去重后的数组。
对数组进行去重操作,只考虑数组中元素为数字或字符串,返回一个去重后的数组。
// ES3
function unique(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
var currElem = arr[i];
if (newArr.indexOf(currElem) < 0) {
newArr.push(currElem);
}
}
return newArr;
}
console.log(unique([1, 2, 1, 3]));
// ES5
function unique(arr) {
return arr.filter(function (elem, index) {
return arr.indexOf(elem) === index
});
}
console.log(unique([1, 2, 1, 3]));
// ES6
var arr = [1, 2, 1, 3];
console.log(Array.from(new Set(arr)));
// ES7
var arr = [1, 2, 1, 3];
console.log([...new Set(arr)]);给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
需要维护一个对象来记录每一个元素出现的次数,使用元素的值作为key,元素出现的次数作为value。之后再遍历这个对象,找到value为1的key。对应的key就是那个元素。
function singleNumber(nums) {
const obj = {};
for (let i = 0; i < nums.length; i++) {
obj[nums[i]] = obj[nums[i]] ? obj[nums[i]] + 1 : 1;
}
for (let key in obj) {
if (obj[key] === 1) {
return Number(key); // 由于 key 是 string ,因此我们这里需要转化下
}
}
}
console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8])); // 8上面那种解法,创建了一个新的对象来储存结果,如果想不使用额外空间,明显是不行的。那么有没有办法可以只使用原来的数组来实现这个功能呢? 解决方案:异或操作
1.异或运算满足交换律、结合律。
1^2^...^n^...^n^...^1000,无论这两个n出现在什么位置,都可以转换成为1^2^...^1000^(n^n)的形式。
2.其次,对于任何数x,都有x^x=0,x^0=x。
所以1^2^...^n^...^n^...^1000 = 1^2^...^1000^(n^n)= 1^2^...^1000^0 = 1^2^...^1000(即序列中除了n的所有数的异或)。异或运算是对于二进制数字而言的,比如说一个有两个二进制a、b,如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
而javascript的按位异或(即^操作)操作,则会对两个数字相应的每一对比特位执行异或操作。
比如说 1 ^ 2,本质上其实是1和2的每一对比特位执行异或操作,等价于下面
00000000000000000000000000000001 // 数字1对应的二进制
^ 00000000000000000000000000000010 // 数字2对应的二进制
= 00000000000000000000000000000011 // 数字3对应的二进制
复制代码因此1^2的结果就为3啦。
那么如果两个相同的数字进行异或操作,结果就可想而知,答案为0啦。
如果是0和任何一个数字异或呢?结果是数字本身。我们只需要遍历数组,将所有的值取异或,最终剩下的值,就是那个只出现一次的数字。 假设我们有一个数组,里面元素为[a, a, c, c, b, b, d]。那么我们对数组里的所有元素进行按位异或操作,即a ^ a ^ c ^ c ^ b ^ b ^ d,是不是就等价于0 ^ 0 ^ 0 ^ d = d。而d就是数组里只出现一次的元素。 那么我们可以扩展一下,对于任意满足某个元素只出现一次以外,其余每个元素均出现两次的数组,是不是可以通过这种方式来得到那个只出现一次的元素。
我们知道,两个相同的数字进行按位异或操作,得到的结果为0。并且任何数字与0进行按位异或,得到的结果是数字本身。那么假设我们有数组[a, b, b, a, c],将数组所有元素进行按位异或操作,即a ^ b ^ b ^ a ^ c,结果是不是等价于0 ^ c = c。同理可得,我们一个数组里只有某个元素只出现一次,其他都出现两次,那么将数组的所有元素都进行按位异或操作,那么结果是不是就等于那个只出现一次的元素。
/**
* 只存在一次的数字
* https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/1/array/25/
* @ param {number[]} nums
* @ return {number}
*/
function singleNumber(nums) {
for (let i = 1; i < nums.length; i++) {
nums[0] ^= nums[i];
}
return nums[0];
};
console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8]));// 实现一个flatten方法,使得输入一个数组,该数组里面的元素也可以是数组,该方法会输出一个扁平化的数组。
// Example
let givenArr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
let outputArr = [1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
// 实现flatten方法使得
flatten(givenArr)——>outputArrfunction flatten(arr){
var res = [];
for(var i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
// concat() 方法用于连接两个或多个数组。返回一个新数组。
res = res.concat(flatten(arr[i]));
}else{
res.push(arr[i]);
}
}
return res;
}function flatten(arr){
// prev 上一次调用回调时返回的累积值。如果没有提供初始值,则将使用数组中的第一个元素。item 数组中正在处理的元素。
// array.reduce(function(accumulator, currentValue, currentIndex, arr), initialValue)
// accumulator 和currentValue的取值有两种情况:
// 如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;
// 如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
return arr.reduce(function(prev,item){
return prev.concat(Array.isArray(item) ? flatten(item) : item);
},[]);
}function flatten(arr){
while(arr.some(item => Array.isArray(item))){
arr = [].concat(...arr);
}
return arr;
}异步函数并行执行,并控制并行数量
现在有个场景:
请你实现一个并发请求函数concurrencyRequest(urls, maxNum),要求如下:
要求最大并发数 maxNum 每当有一个请求返回,就留下一个空位,可以增加新的请求 所有请求完成后,结果按照 urls 里面的顺序依次打出(发送请求的函数可以直接使用fetch即可)
const preloadManger = (urls, maxCount = 5) => {
let count = 0; // 计数 -- 用于控制并发数
const createTask = () => {
if (count < maxCount) {
const url = urls.pop(); // 从请求数组中取值
if (url) {
// 无论请求是否成功,都要执行taskFinish
loader(url).finally(taskFinish);
// 添加下一个请求
count++;
createTask();
}
}
};
const taskFinish = () => {
count--;
createTask();
};
createTask();
};
// 进行异步请求
const loader = async (url) => {
const res = await fetch(url).then(res=>res.json());
console.log("res",res);
return res
}
const urls = [];
for (let i = 1; i <= 20; i++) {
urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`);
}
preloadManger(urls, 5)// 简洁版pLimit
// 异步逻辑并行执行,并控制并行数量
// 一个队列来保存任务,有两个时机考虑触发任务执行:
// 1. 开始的时候一次性执行最大并发数的任务
// 2. 然后每执行完一个启动一个新的
const shortPLimit = (concurrency) => {
// 传入并发数量
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
throw new TypeError('Expected `concurrency` to be a number from 1 and up');
}
// 添加的并发任务要进行排队,所以我们准备一个 queue
const queue = [];
// 记录当前在进行中的异步任务
let activeCount = 0;
// 下一步处理自然就是把活跃任务数量减一,然后再跑一个任务
const next = () => {
activeCount--;
if (queue.length > 0) {
// 如果队列中还有任务,就再跑一个
queue.shift()();
}
};
// 计数,运行这个函数,改变最后返回的那个 promise 的状态
const run = async (fn, resolve, ...args) => {
activeCount++;
// 运行传入的异步函数
const result = (async () => fn(...args))();
resolve(result);
try {
// 等待异步函数执行完
await result;
} catch {}
// 执行完之后进行下一步处理
next();
};
// 把一个异步任务添加到 queue 中,并且只要没达到并发上限就再执行一批任务
const enqueue = (fn, resolve, ...args) => {
queue.push(run.bind(null, fn, resolve, ...args));
// 为了保证并发数量能控制准确,要等全部的微任务执行完再拿 activeCount 和 queue.length 来判断
(async () => {
await Promise.resolve();
if (activeCount < concurrency && queue.length > 0) {
// 如果活跃任务数量小于并发数量,就再跑一个
queue.shift()();
}
})();
};
// 返回一个添加并发任务的函数,我们把它叫做 generator。
// 依旧希望返回返回任务函数的promise的结果
const generator = (fn, ...args) =>
new Promise((resolve) => {
enqueue(fn, resolve, ...args);
});
return generator;
};// 完整版pLimit
// 异步逻辑并行执行,并控制并行数量
// 一个队列来保存任务,有两个时机考虑触发任务执行:
// 1. 开始的时候一次性执行最大并发数的任务
// 2. 然后每执行完一个启动一个新的
const pLimit = (concurrency) => {
// 传入并发数量
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
throw new TypeError('Expected `concurrency` to be a number from 1 and up');
}
// 添加的并发任务要进行排队,所以我们准备一个 queue
const queue = [];
// 记录当前在进行中的异步任务
let activeCount = 0;
// 下一步处理自然就是把活跃任务数量减一,然后再跑一个任务
const next = () => {
activeCount--;
if (queue.length > 0) {
// 如果队列中还有任务,就再跑一个
queue.shift()();
}
};
// 计数,运行这个函数,改变最后返回的那个 promise 的状态
const run = async (fn, resolve, ...args) => {
activeCount++;
// 运行传入的异步函数
const result = (async () => fn(...args))();
resolve(result);
try {
// 等待异步函数执行完
await result;
} catch {}
// 执行完之后进行下一步处理
next();
};
// 把一个异步任务添加到 queue 中,并且只要没达到并发上限就再执行一批任务
const enqueue = (fn, resolve, ...args) => {
queue.push(run.bind(null, fn, resolve, ...args));
// 为了保证并发数量能控制准确,要等全部的微任务执行完再拿 activeCount 和 queue.length 来判断
(async () => {
await Promise.resolve();
if (activeCount < concurrency && queue.length > 0) {
// 如果活跃任务数量小于并发数量,就再跑一个
queue.shift()();
}
})();
};
// 返回一个添加并发任务的函数,我们把它叫做 generator
const generator = (fn, ...args) =>
new Promise((resolve) => {
enqueue(fn, resolve, ...args);
});
// 为 generator 添加一些属性,方便外部获取当前的状态
Object.defineProperties(generator, {
activeCount: {
get: () => activeCount
},
pendingCount: {
get: () => queue.length
},
// 提供了一个清空任务队列的函数
clearQueue: {
value: () => {
queue.length = 0;
}
}
});
return generator;
};
// 测试代码
const limit = pLimit(2);
function asyncFun(value, delay) {
return new Promise((resolve) => {
console.log('start ' + value);
setTimeout(() => resolve(value), delay);
});
}
(async function () {
const arr = [
limit(() => asyncFun('aaa', 2000)),
limit(() => asyncFun('bbb', 3000)),
limit(() => asyncFun('ccc', 1000)),
limit(() => asyncFun('ccc', 1000)),
limit(() => asyncFun('ccc', 1000))
];
const result = await Promise.all(arr);
console.log(result);
})();有 8 个细胞,状态由 0(无活性)或 1(有活性)表示。细胞呈直线排列(注意不是环形!!!)。每天,每个细胞都会与其相邻细胞(邻居)竞争。整数值1代表活跃细胞,0代表不活跃细胞。如果两个邻居同为活跃或不活跃,该细胞第二天就会变为不活跃状态。否则,第二天它就会变为活跃状态。两端的两个细胞只有一个相邻细胞,因此另一个细胞可假定始终为不活跃状态。
示例:
8
1 0 0 0 0 1 0 0
1最终状态:[0,1,0,0,1,0,1,0]
更新规则: 每个细胞下一轮的状态,由左右相邻细胞当前状态决定: 若左右状态不同(一个 0、一个 1 )→ 下一轮变为 1(激活)。 若左右状态相同(都是 0 或都是 1 )→ 下一轮变为 0(失活)。 需要模拟 days 天后的细胞状态,输出最终 8 个细胞的 0/1 序列。
模拟细胞每天根据邻居状态变化的过程,本质是多轮的状态迭代问题,核心是根据规则迭代更新细胞状态,类似「生命游戏」简化版,重点在理解规则、正确处理环形邻居,以及保证每轮状态更新的正确性 。
更新规则: 每个细胞下一轮的状态,由左右相邻细胞当前状态决定: 若左右状态不同(一个 0、一个 1 )→ 下一轮变为 1(激活)。 若左右状态相同(都是 0 或都是 1 )→ 下一轮变为 0(失活)。 要求:给定初始状态和天数,模拟迭代 days 次后的最终状态。
输入: 第一行:细胞数量(固定为 8,可忽略或直接用长度 8 处理 )。 第二行:8 个数字,代表细胞初始状态(0/1 序列 )。 第三行:迭代的天数 days。 输出: 迭代 days 次后,8 个细胞的状态(0/1 序列 )
核心逻辑 循环迭代:按天数重复更新细胞状态,每次迭代都要基于上一轮的完整状态计算新状态(不能边更新边覆盖,否则会影响后续细胞判断 )。
邻居逻辑不是环形,是线性! 对于两端细胞(i=0 或 i=n-1): i=0:左邻居视为 0,右邻居是 cells [1] i=n-1:右邻居视为 0,左邻居是 cells [n-2] 中间细胞(0 <i < n-1):左右邻居是 cells [i-1] 和 cells [i+1]
如果是环形邻居处理:用取模 % 或边界判断,让第一个细胞的左邻居是最后一个,最后一个的右邻居是第一个。
状态推导:对每个细胞,比较左右邻居状态,按规则生成新状态。
function main(input) {
const lines = input.trim().split('\n').filter(line => line.trim() !== '');
const cellStatesLine = lines[1];
const daysLine = lines[2];
let cells = cellStatesLine.split(' ').map(Number);
const days = parseInt(daysLine, 10);
const n = cells.length;
for (let d = 0; d < days; d++) {
const newCells = [];
for (let i = 0; i < n; i++) {
let left, right;
if (i === 0) {
// 左端细胞:左邻居视为 0,右邻居是 cells[1]
left = 0;
right = cells[1];
} else if (i === n - 1) {
// 右端细胞:右邻居视为 0,左邻居是 cells[n-2]
left = cells[n - 2];
right = 0;
} else {
// 中间细胞:左右邻居正常取
left = cells[i - 1];
right = cells[i + 1];
}
newCells[i] = left !== right ? 1 : 0;
}
cells = newCells;
}
process.stdout.write(cells.join(' ') + '\n');
}
// 输入监听逻辑(保留)
process.stdin.resume();
process.stdin.setEncoding("utf-8");
var stdin_input = "";
process.stdin.on("data", function (input) {
stdin_input += input;
});
process.stdin.on("end", function () {
main(stdin_input);
});
// 输入:
// 8
// 1 0 0 0 0 1 0 0
// 1
// 执行流程:
// 细胞 0(i=0):左 = 0,右 = cells [1]=0 → 左右相同 → 0
// 细胞 1(i=1):左 = cells [0]=1,右 = cells [2]=0 → 不同 → 1
// 细胞 2(i=2):左 = cells [1]=0,右 = cells [3]=0 → 相同 → 0
// 细胞 3(i=3):左 = cells [2]=0,右 = cells [4]=0 → 相同 → 0
// 细胞 4(i=4):左 = cells [3]=0,右 = cells [5]=1 → 不同 → 1
// 细胞 5(i=5):左 = cells [4]=0,右 = cells [6]=0 → 相同 → 0
// 细胞 6(i=6):左 = cells [5]=1,右 = cells [7]=0 → 不同 → 1
// 细胞 7(i=7):左 = cells [6]=0,右 = 0 → 相同 → 0如果是环形排列解法:
function main(input) {
// 解析输入:取前 3 行(数量、状态、天数)
const lines = input.trim().split('\n').filter(line => line.trim() !== '');
// 第一行是数量(题目中固定为8,可忽略,但需确保第二行是状态)
const cellStatesLine = lines[1];
const daysLine = lines[2];
let cells = cellStatesLine.split(' ').map(Number);
const days = parseInt(daysLine, 10);
const n = cells.length; // 应为 8
// 逐天更新细胞状态(原逻辑保留)
for (let d = 0; d < days; d++) {
const newCells = [];
for (let i = 0; i < n; i++) {
const left = cells[(i - 1 + n) % n];
const right = cells[(i + 1) % n];
newCells[i] = left !== right ? 1 : 0;
}
cells = newCells;
}
// 输出最终状态
process.stdout.write(cells.join(' ') + '\n');
}
// 输入监听逻辑(确保收集完整输入)
process.stdin.resume();
process.stdin.setEncoding("utf-8");
var stdin_input = "";
process.stdin.on("data", function (input) {
stdin_input += input;
});
process.stdin.on("end", function () {
main(stdin_input);
});给定缓存的最大容量和页请求数组,计算缓存未命中的次数。当请求的页在缓存中找不到时,发生缓存未命中。初始时缓存为空 。
操作系统使用先进先出(FIFO)缓存进行虚拟内存管理。当请求的页不在缓存中且缓存已满时,缓存中最久未使用(存在时间最长)的页会被移除,为请求的页腾出空间。若缓存未满,请求的页可直接加入缓存。同一页在缓存中最多出现一次 。
输入说明:
输入第一行是正整数 page_requests_size,表示页请求的总数N。
第二行包含 N 个用空格分隔的正整数 page_requests[0], page_requests[1] ... page_requests[N - 1],代表 N 次页请求。
最后一行是整数 max_cache_size,表示缓存的容量 。
输出说明:
输出一个整数,表示缓存未命中的次数 。
注意事项:
假设 page_requests 数组中的页编号在 1 - 50 范围内。page_requests 中索引为 i 的页,在索引为 i + 1 的页之前被请求 。
示例:
6
1 2 1 3 1 2
2输出需按规则计算缓存未命中次数(如前面分析的流程,输出 5 这类结果 )。
整体就是让你用代码实现 FIFO 缓存模拟,统计页请求时的未命中次数,属于经典的 “缓存置换算法模拟” 编程题 。
function main(input) {
// 拆分输入为行,过滤空行
const lines = input.trim().split('\n').filter(line => line.trim() !== '');
// 解析输入(严格按题目要求的三行)
const pageRequestsSize = parseInt(lines[0], 10);
const pageRequests = lines[1].split(' ').map(Number);
const maxCacheSize = parseInt(lines[2], 10);
// 校验输入长度(可选但推荐)
if (pageRequests.length !== pageRequestsSize) {
process.stdout.write("0"); // 输入非法时返回 0(或按题意处理)
return;
}
// FIFO 缓存实现(用数组模拟队列)
const cache = [];
let cacheMisses = 0;
for (const page of pageRequests) {
if (!cache.includes(page)) {
cacheMisses++; // 未命中计数
if (cache.length >= maxCacheSize) {
cache.shift(); // 缓存满时移除队首(最早进入的页面)
}
cache.push(page); // 新增页面到队尾
}
// 命中时不处理(FIFO 不调整顺序)
}
// 输出结果
process.stdout.write(cacheMisses.toString());
}
// 输入监听逻辑(保持原样)
process.stdin.resume();
process.stdin.setEncoding("utf-8");
let stdin_input = "";
process.stdin.on("data", (input) => {
stdin_input += input;
});
process.stdin.on("end", () => {
main(stdin_input);
});
// 测试代码
// 输入:
// 6
// 1 2 1 3 1 2
// 2
// 执行过程:
// 请求1 → 未命中(缓存: [1])→ 计数1
// 请求2 → 未命中(缓存: [1,2])→ 计数2
// 请求1 → 命中(缓存不变)
// 请求3 → 未命中(缓存满,移除1 → [2,3])→ 计数3
// 请求1 → 未命中(缓存满,移除2 → [3,1])→ 计数4
// 请求2 → 未命中(缓存满,移除3 → [1,2])→ 计数5
// 输出:5(与题目示例一致)