JS 习题1000
-
传入任意数量的整数参数,求出其中满足被3和5整除的参数之和
let total = 0; function myFun(...args) { //console.log(args); args.forEach((value) => { if ((value % 3) + (value % 5) === 0) return (total += value); }); } myFun(15, 45, 30, 40); -
十秒之内每秒返回一个不重复的两位随机小数num(0 <= **num **<= 60)
const collection = []; let counter = 0;// 计数器 let timer = setInterval(myFun, 1000);// 定时循环执行 myFun function myFun() { let num = (Math.random() * 61).toFixed(2); if (num > 60) num = 60; if (collection.indexOf(num) === -1) collection.push(num); console.log(collection[counter]); counter++; // 保证 timer 异步执行 10次 if (counter === 10) { clearInterval(timer); } } myFun(); -
从一个长字符串中随机抽出4个不重复字符组成一个新字符串
function get4str(str) { let newStr = ""; const arr = str.split(""); let len = arr.length; while (newStr.length !== 4) { let index = Math.round(Math.random() * len);// 放在while循环外会导致无限循环 if (newStr.search(arr[index]) === -1) { newStr += arr[index]; } } return newStr; } get4str("74357huisadb4354539780453higdfhj4398453"); -
输入一个随机正整数,将其重组为一个最大正整数(324 => 432)
function bigger(num){ // 判断是否个位数以及输入是否数字 if (num < 10 && typeof(num) !== "number") return -1; // 获取参数转为数组 const arr = String(num).split(""); // 利用 new set(arr) 数组去重,若集合长度为 1 则说明每位的数一样,返回 -1 const mySet = new Set(arr); if (mySet.length === 1) return -1; // 我们利用先arr.sort()方法排序得到从小到大排序,再利用reverse()方法得到从大到小排序。 let bigArr = arr.sort().reverse(); let bigNum = Number(bigArr.join("")); // 利用 三元运算符 判断用户输入数字和重组的最大数字是否相等,相等返回 -1,否则返回 bigNum let result = (bigNum === num) ? -1 : bigNum; return result; }本题提供了一个小思路:先考虑过滤掉用户的无用输入和非法输入(一般输入和特殊输入为合法输入),再考虑使用哪几种方法得到目标数据,最后操作目标数据输出不同结果。
-
输入一个包含重复元素的数组,输出每个元素出现的次数,再按照次数从高到低排序,结果输出为以对象为元素的数组
/* 我的解题思路: 第一步,获取数组遍历迭代拿到对象 {元素: 出现次数, 元素: 出现次数, 元素: 出现次数, ...} 第二步,将前面拿到的对象用 for in 遍历输出一个新数组 [{元素: 出现次数}, {元素: 出现次数}, {元素: 出现次数}, ...] 最后一步,把第二步拿到的数组用 sort(比较函数) 进行排序输出最终结果 */ function myFun(arr){ const obj = arr.reduce((init, index) => { // 利用数组的 reduce 方法可以很容易的返回一个 预期的对象,而不是像 map(callback) 一样只能返回一个数组 if (index in init) {// if (init[index]) 效果一样; 这里的整个 if 语句可以替换成三元运算符 init[index]++;// 键存在则键值+1 } else { init[index] = 1;// 键不存在则键值初始化为1 } return init// 必须 return 结果 },{})// 初始值为空对象保存每个每个数组元素的出现次数 const newArr = []; //获取对象作为元素的新数组 for (let i in obj) { if (obj.hasOwnProperty(i)) { newArr.push({item: i, times: obj[i]})// 解构赋值 } } return newArr.sort(function (a, b) {return a.times - b.times}).reverse();// 输出从大到小排序后的新数组,请注意 times 不要打成 tiems!!! } //优化版 function myFun(arr){ // for of 加上 三元运算符 轻松搞定第一步 const obj = {}; for (item of arr) { obj[item] = (obj[item]) ? obj[item] + 1 : 1;// 注意 obj[item] + 1 不能是 obj[item]++ }; // 注意 for in 遍历加一层 自有属性 判断 const newArr = []; for (let i in obj) { if (obj.hasOwnProperty(i)) { newArr.push({item: i, times: obj[i]})// 解构赋值 } } //最后一步弃用 reverse(),直接 b.times - a.times 搞定 return newArr.sort((a, b) => b.times - a.times); }思路二:大同小异的办法
/* 第一步:获取数组再用 Array.from(new Set(arr)) 得到集合式数组 第二步:利用 map(item) 遍历集合数组项,遍历一次 push 一个 {key: item, val: tiems} 到最终输出的结果数组中 第三步:和我的思路一模一样, sort() 排序完事 */ function ansFun(arr) { let shortAry = Array.from(new Set(arr));// 不同点是:我第一步拿到一个对象,他这里拿到一个集合数组 let endAry = []; shortAry.map((item) => {// 他第二部顺理成章用 map() 遍历数组项 let obj = { key: null, val: null }; // key 元素,val 元素出现次数 obj.key = item; while (arr.includes(item)) { obj.val++; arr.splice(arr.indexOf(item), 1); } endAry.push(obj);// 和我的想法差不多,最终得到 [{元素: 出现次数}, {元素: 出现次数}, {元素: 出现次数}, ...] }); return endAry.sort((a, b) => b.val - a.val); } -
输入一个字符串统计字符串中出现最多的字符(包含出现次数重复的字符)
function getStrMax(str){ const arr = str.split(""); // for of 加上 三元运算符 轻松搞定第一步 const obj = {}; for (item of arr) { obj[item] = (obj[item]) ? obj[item] + 1 : 1;// 注意 obj[item] + 1 不能是 obj[item]++ }; // 注意 for in 遍历加一层 自有属性 判断 const newArr = []; for (let i in obj) { if (obj.hasOwnProperty(i)) { newArr.push({item: i, times: obj[i]})// 解构赋值 } } //最后一步弃用 reverse(),直接 b.times - a.times 搞定 const decreaseArr = newArr.sort((a, b) => b.times - a.times); // 拿到次数递减数组后,变相的拿到了 最大次数字符项,再加一步判定后续项是不是相同次数 let timesMax = decreaseArr[0].times; /* 这个时候用 arr.filter() 就非常合适出场了, 因为此时 decreaseArr 的数组项是 {item: x, times: y} 并且 decreaseArr 是递减排序好了的结果 */ const endArr = decreaseArr.filter((obj) => obj.times === timesMax); let endItems = ""; endArr.map((obj) => endItems += obj.item) return `出现最多的字符是${endItems.split("")},均出现了${timesMax}次`;// ${object} 会隐式转换object为string }思路二:考虑到字符和出现次数的关系不就是映射吗?那我们直接操作映射看看
/* 第一步:字符串直接利用索引访问,然后创建一个映射实例存储【字符出现次数】的数据。 第二步:for循环遍历字符串,通过判断字符存在与否更新映射的数据 第三步:通过 map.values() 得到所有字符出现次数的数组[3, 2, ...],再利用 Math.max 方法得到最大值 第四步:for of遍历映射,通过判断次数是否等于最大次数得到满足条件的字符数组 第五步:模板字符串输出结果 */ function findMax(str){ const endKeys = []; const strMap = new Map(); let len = str.length; // strMap[str[i]] = mapKeys.includes(str[i]) ? strMap[str[i]] + 1 : 1; 三元运算此处行不通 for (let i = 0; i < len; i++ ) { if (strMap.has(str[i])) { strMap.set(str[i], strMap.get(str[i]) + 1); // 赋值更新映射的值是无效的,这里还得采用 map.set()方法 } else { strMap.set(str[i], 1);// 新增映射key, value初始化为1 } }; // const mapVals = Array.from(strMap.values()); let maxVal = (Math.max).apply(Math, mapVals);// 数组最大值 // for (let [key, val] of strMap) { if (val === maxVal) endKeys.push(key) }; return `出现最多的字符是${endKeys},均出现了${maxVal}次`; }思路三:利用正则表达式
function regFind(str) { str = str.split('').sort(function (a, b) { return a.localeCompare(b) }).join('');// a.localeCompare(b) 如果a排在b的前面返回 -1或-2 ,否则返回 1或2。如果a和b的值一致则返回 0。 const reg = /(\w)\1+/g; // 区分大小写全局匹配至少重复一次的字符 let maxTimes = 0, endStr = ''; // 这里使用 str.replace(reg, callback) 是因为只有 replace 方法支持操作【匹配的子字符串】,由于有修饰符 g 和 $0, $1,意思是全局匹配的子字符串,每个字符字串会单独输出一个数组,$0, $1分别是该数组第一个子字符串项(比如aaa)和第二个字符项(比如a)。 str.replace(reg, function ($0, $1) { // console.log(arguments); 通过调试理解$0, $1 if ($0.length > maxTimes) {// 出现次数大者,覆盖 endStr maxTimes = $0.length; endStr = $1; } else if ($0.length === maxTimes) {// 出现次数相同,则拼接字符 endStr += $1; } // 当$0.length < maxTimes 不做任何操作 }); endStr = endStr.split('');// 转换成数组,目的是给给输出的结果加逗号分隔 return `出现最多的字符是${endStr},均出现了${maxTimes}次`; } // regFind("aaAAAAccccCCDDF");