概述
我也想速成,勤能补拙。一共有大约三十道笔试题,是我想入职华为OD时练习的,虽然后来没去。分为三个难度等级,但愿勤奋如你,能拿到满意的offer。
入门难度
四舍五入
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于0.5,向上取整;小于0.5,则向下取整。
function myParseInt(number1) {
if (typeof number1 === "number") {
const numberString = number1 + "";
const construcNumber = numberString.split(".");
let result = construcNumber[0];
if (construcNumber[1]) {
if (construcNumber[1][0] >= 5) {
result = Number(result) + 1;
}
}
return Number(result);
}
}
输入一个正整数,计算出数据在内存中存储时1的个数。
function transformToBinary(number2) {
if (typeof number2 === "number") {
const BinaryNumber = number2.toString(2);
let count = 0;
for (let i = 0; i <= BinaryNumber.length; i++) {
if (BinaryNumber[i] === "1") {
count += 1;
}
}
return count;
}
}
数组排序
给定一个数字数组,对齐进行排序,0表示升序排序,1表示降序牌序
function mySort(numberArray, mode) {
const midNum = numberArray[0];
if (!numberArray.length) {
return "";
}
const leftArray = [];
const rightArray = [];
for (let i = 1; i < numberArray.length; i++) {
if (numberArray[i] <= midNum) {
leftArray.push(numberArray[i]);
} else {
rightArray.push(numberArray[i]);
}
}
if (mode) {
return [...mySort(rightArray, mode), midNum, ...mySort(leftArray, mode)];
}
return [...mySort(leftArray, mode), midNum, ...mySort(rightArray, mode)];
}
简单难度
逆序输出number
输入一个整数,将这个整数以字符串的形式逆序输出,程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001
function myNumberToRevserString(testNumber) {
const numberArray = String.prototype.split.call(testNumber, "");
return numberArray.reverse().join("");
}
字符串反转
接受一个只包含小写字母的字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
function stringToReverse(testString) {
const regex = /^[a-z]+$/g;
if (regex.test(testString) && testString.length <= 1000) {
return testString.split("").reverse().join("");
} else {
return new Error("请输入仅含小写字母,并且长度小于1000的字符串");
}
}
瓶子换水喝
“某商店规定:三个空汽水瓶可以换一瓶汽水。
小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”
答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。
然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。
如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?
let DrinkCount = 0;
function DrinkSoda(numberBottle, count) {
// 手里的瓶子够换几瓶
const int = parseInt(numberBottle / 3);
// 手里剩下的瓶子
const remain = numberBottle % 3;
// 换一次喝完后手里有的瓶子
const newNumberBottle = int + remain;
if (newNumberBottle >= 3) {
// 下一轮接着换
DrinkSoda(newNumberBottle, count + int);
} else if (newNumberBottle === 2) {
// 找老板借一瓶,最后喝一瓶,结束
DrinkCount = count + int + 1;
} else {
DrinkCount = count + int;
}
return DrinkCount;
}
斐波那契数列
有一只兔子(刚出生),从出生后第3个月起每个月都生一只兔子,小兔子(假设都可以生兔子,不分公母)长到第三个月后每个月又生一只兔子,假如兔子都不死,问每个月的兔子总数为多少?
经过推理我们发现,当月新增的兔子数量总是上上个月的兔子数量总和,
所以当月的兔子数量就是上上个月的兔子数量加上个月的兔子数量。
递归
function fb(n, num1 = 1, num2 = 1) {
if(n == 0) return 0
if (n <= 2) {
return num2
} else {
return fb(n - 1, num2, num1 + num2)
}
}
循环
function birthRabbbit(months) {
let rabbits = [];
for (let i = 0; i <= months - 1; i++) {
if (i <= 1) {
rabbits.push(1);
} else {
rabbits.push(rabbits[i - 1] + rabbits[i - 2]);
}
}
return rabbits[months - 1];
}
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数
它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。s
输入n,请输出n以内(含n)完全数的个数。计算范围, 0 < n <= 500000
function getPerfectNumber(n) {
const perfectNumber = [];
// 1肯定不满足条件,1除去本身没有因子
for (let j = 2; j <= n; j++) {
// 1一定是因子,先将1放入
const factorJ = [1];
// 求一个数的因子个数,只需要遍历到sqrt(j)也就是根号下j
for (let i = 2; i <= Math.sqrt(j); i++) {
if (j % i === 0) {
factorJ.push(i);
factorJ.push(j / i);
}
}
let factorAdd = factorJ.reduce((pre, current) => pre + current, 0);
if (factorAdd === j) {
perfectNumber.push(j);
}
}
return perfectNumber.length;
}
公共子串
给定两个只包含小写字母的字符串,计算两个字符串的最大公共子串的长度。
注:子串的定义指一个字符串删掉其部分前缀和后缀(也可以不删)后形成的字符串。
输入 asdfas werasdfaswer
输出 6
function stringMaxCommonFactor(string1, string2) {
let minString = string1;
let maxString = string2;
let maxlength = 0;
if (string1.length >= string2.length) {
minString = string2;
maxString = string1;
}
// j为要截取的字符串长度,依次减小检验字符串的长度
for (let j = minString.length; j >= 0; j--) {
// i为截取字符串的开始位置
for (let i = 0; i < minString.length - j; i++) {
// slice [start, end) 所以要加1
let result = minString.slice(i, i + j + 1);
if (maxString.indexOf(result) >= 0) {
return result.length;
}
}
}
return maxlength;
}
任何一个整数m的立方都可以写成m个连续奇数之和。
function nikochusTheorem(m) {
const pow3 = Math.pow(m, 3);
const avarge = parseInt(pow3 / m);
const result = [];
for (let i = avarge - m + 1; i <= avarge + m - 1; i = i + 2) {
result.push(i);
}
return result;
}
统计字符串中大写字母的个数
function stringToUpcode(string1) {
const stringArray = string1.split("");
const length = stringArray.length;
let count = 0;
// 通过正则判断是否是大写字母
// for(let i = 0; i < length; i++) {
// const regex = /[A-Z]+/g
// if(regex.test(stringArray[i])) {
// count++
// }
// }
for (let i = 0; i < length; i++) {
const charCodeAt = stringArray[i].charCodeAt();
// 转为unicode编码号,通过65到90判断是否是大写字母
if (charCodeAt >= 65 && charCodeAt <= 90) {
count++;
}
}
return count;
}
字符串翻转
输入 I am a student 输出 tneduts a ma
function reverseString(sourceStr) {
const strArr = sourceStr.split(" ").reverse();
const resultStr = strArr
.map((item) => {
return item.split("").reverse().join("");
})
.join(" ");
return resultStr;
}
最小公倍数
输入两个值,求最小公倍数
更相减损法求出最大公约数,然后n * m / 最大公约数 就是最小公倍数
更相减损法就是用大的减去小的,差值代替大值,再减,直到两个值相等,输出的就是最大公约数
function minMultiple(n, m) {
function maxPublicFactor(n, m) {
let diff = 0;
let other = 0;
if (n > m) {
diff = n - m;
other = m;
} else if (n < m) {
diff = m - n;
other = n;
} else {
return n;
}
return maxPublicFactor(diff, other);
}
return (n * m) / maxPublicFactor(n, m);
}
m苹果分n盘
把m个同样的苹果,放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法 7个苹果,三个盘子, 5,1,1和 1,5,1是同一种分法
数据范围 0 < m <= 10 1 <= n <= 10
如果有1个空盘子,转换为 m个苹果和n - 1 个盘子
如果全部放满,转换为 m - n个苹果 和 n个盘子
function divideApple(apples, plates) {
if (apples === 0 || plates === 0) {
return 1
}
if (apples === 1 || plates === 1) {
return 1
}
if (apples < plates) {
return divideApple(apples, plates - 1)
}
return divideApple(apples - plates, plates) + divideApple(apples, plates - 1)
}
100钱买100鸡
公鸡5元,母鸡3元,3只小鸡1元钱,100元买100只鸡,钱全部花完,有多少种买法?分别是?
转换为整数 公鸡15,母鸡9 小鸡1元,300元买100只鸡,
function buy100Chicken() {
const max_a = parseInt(300 / 15);
const max_b = parseInt(300 / 9);
console.log(max_a, max_b)
const result = [];
for (let a = 0; a <= max_a; a++) {
for (let b = 0; b <= max_b; b++) {
for (let c = 0; c <= 100; c++) {
if (a + b + c === 100) {
if (a * 15 + b * 9 + c * 1 === 300) {
result.push([a, b, c])
}
}
}
}
}
return result
}
根据输入的日期,计算这是一年的第多少天?
输入 2012-12-31 输出 366
function computedDay(dayString) {
const timeArray = dayString.split('-');
const leapYear = [31,60,91,121,152,182,213,244,274,305,335,366];
const year = [31,59,90,120,151,181,212,243,273,304,334,365];
// 能被4整除但不能被100整除,就是闰年
if(Number(timeArray[0]) % 4 === 0 && Number(timeArray[0] % 100 !== 0) ) {
if(timeArray[1] - 2 >= 0) {
return leapYear[timeArray[1] - 2] + Number(timeArray[2])
} else {
return Number(timeArray[2])
}
} else {
if(timeArray[1] - 2 >= 0) {
return year[timeArray[1] - 2] + Number(timeArray[2])
} else {
return Number(timeArray[2])
}
}
}
计算字符串中最长的回文字符串长度
function palindromeString(string1) {
const length = string1.length;
// 截取字符串的长度,从最长开始
for (let i = length; i >= 1; i--) {
// 截取字符串的开始位置,从0开始
for (let j = 0; j <= length - i; j++) {
let sliceString = string1.slice(j, j + i)
if (sliceString.split('').reverse().join('') === sliceString) {
return sliceString.length;
}
}
}
return 1
}
走棋盘
计算nm棋盘格子,n表示横向有n个格子,m表示纵向有m个格子, 沿着格子边缘从左上角走到右下角,总共有多少种走法,要求不能走回头路(即只能往右和往下走,不能往左和往上)
向下走一格,转变为 nm-1的棋盘 向右走一格,转变为 (n-1)*m的棋盘
function chessboard(n, m) {
if (n === 0) {
return 1
}
if (m === 0) {
return 1
}
return chessboard(n - 1, m) + chessboard(n, m - 1)
}
求一个number类型数字对应的二进制数字中1的最大连续数,
例如3的二进制为00000011,最大连续2个1
function getNumberContinuity1(number1) {
// 转为二进制
const BinaryString = number1.toString(2);
const length = BinaryString.length;
for(let i = length; i >= 1; i--) {
// 生成一个长度逐渐变短的全为1的字符串
const testString = '1'.repeat(i)
// 去匹配BinaryString
if(BinaryString.includes(testString)) {
return testString.length
}
}
}
密码强度
密码按如下规则进行计分,并根据不同的得分为密码进行安全等级划分。
一、密码长度:
5 分: 小于等于4 个字符
10 分: 5 到7 字符
25 分: 大于等于8 个字符
二、字母:
0 分: 没有字母
10 分: 存在小(大)写字母
20 分: 存在大小写混合字母
三、数字:
0 分: 没有数字
10 分: 1 个数字
20 分: 大于1 个数字
四、符号:
0 分: 没有符号
10 分: 1 个符号
25 分: 大于1 个符号
五、奖励:
2 分: 字母和数字
3 分: 字母、数字和符号
5 分: 大小写字母、数字和符号
最后的评分标准:
大于等于 90: 非常安全
大于等于 80: 安全(Secure)
大于等于70: 非常强
大于等于60: 强(Strong)
大于等于50: 一般(Average)
大于等于25: 弱(Weak)
大于等于0: 非常弱
对应输出为:
VERY_SECURE
SECURE
VERY_STRONG
STRONG
AVERAGE
WEAK
VERY_WEAK
符号包含如下: (ASCII码表可以在UltraEdit的菜单view->ASCII Table查看)
!"#$%&'()*+,-./ (ASCII码:0x21~0x2F)
:;<=>?@ (ASCII码:0x3A~0x40)
[]^_` (ASCII码:0x5B~0x60)
{|}~ (ASCII码:0x7B~0x7E)
function passwordEvaluation(passwordString) {
// 长度判断
function passwordLength(password) {
const length = password.length;
if (length <= 4) {
return 5;
} else if (5 <= length && length <= 7) {
return 10;
} else if (length >= 8) {
return 25;
}
}
// 字母判断
function passwordLetter(password) {
const upCode = /[A-Z]/g;
const lowCode = /[a-z]/g;
const upCodeResult = upCode.test(password);
const lowCodeResult = lowCode.test(password);
if (upCodeResult && lowCodeResult) {
return 20;
} else if (upCodeResult || lowCodeResult) {
return 10;
} else {
return 0;
}
}
// 数字判断
function passwordNumber(password) {
const numberRegex = /[0-9]/;
let numberCount = 0;
for (let i = 0; i < password.length; i++) {
if (numberRegex.test(password[i])) {
numberCount += 1;
}
}
if (numberCount === 0) {
return 0;
} else if (numberCount === 1) {
return 10;
} else {
return 20;
}
}
// 字符判断
function passwordSymbol(password) {
const length = password.length;
let symbolCount = 0;
for (let i = 0; i < length; i++) {
const number16 = password[i].charCodeAt();
// 0x开头表示16进制 0表示8进制 0b表示2进制
if (
(number16 >= 0x21 && number16 <= 0x2f) ||
(number16 >= 0x3a && number16 <= 0x40) ||
(number16 >= 0x5b && number16 <= 0x60) ||
(number16 >= 0x7b && number16 <= 0x7e)
) {
symbolCount += 1;
}
}
if (symbolCount === 0) {
return 0;
} else if (symbolCount === 1) {
return 10;
} else {
return 25;
}
}
const lengthCode = passwordLength(passwordString);
const letterCode = passwordLetter(passwordString);
const numberCode = passwordNumber(passwordString);
const symbolCode = passwordSymbol(passwordString);
// 附加奖励分
function passwordReward(password) {
if (letterCode === 20 && numberCode >= 10 && symbolCode >= 10) {
return 5;
} else if (letterCode === 10 && numberCode >= 10 && symbolCode >= 10) {
return 3;
} else if (letterCode >= 10 && numberCode >= 10) {
return 2;
}
return 0;
}
const rewardCode = passwordReward(passwordString);
// 最终得分
const passwrodCode =
lengthCode + letterCode + numberCode + symbolCode + rewardCode;
if (passwrodCode >= 90) {
return "VERY_SECURE";
} else if (passwrodCode >= 80) {
return "SECURE";
} else if (passwrodCode >= 70) {
return "VERY_STRONG";
} else if (passwrodCode >= 60) {
return "STRONG";
} else if (passwrodCode >= 50) {
return "AVERAGE";
} else if (passwrodCode >= 25) {
return "WEAK";
} else if (passwrodCode >= 0) {
return "VERY_WEAK";
}
}
中等难度
进制转换
十进制转为十六进制
短除法求余反转
function tenToSixteen(number1) {
const reaminArray = [];
const valueArray = [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
"A",
"B",
"C",
"D",
"E",
"F",
];
function division(number10) {
reaminArray.push(number10 % 16);
if (Math.floor(number10 / 16) > 0) {
division(Math.floor(number10 / 16));
}
}
division(number1);
let result = "0x";
for (let i = reaminArray.length - 1; i >= 0; i--) {
result = result + valueArray[reaminArray[i]];
}
return result;
}
十六进制转为十进制
遍历求指数
function sixteenToTen(number16) {
const numberArray = number16.split("").reverse();
const valueMap = {
0: 0,
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
6: 6,
7: 7,
8: 8,
9: 9,
A: 10,
B: 11,
C: 12,
D: 13,
E: 14,
F: 15,
};
let result = 0;
for (let i = 0; i < numberArray.length; i++) {
if (numberArray[i] === "x") {
break;
}
result += valueMap[numberArray[i]] * Math.pow(16, i);
}
}
输入一个正整数,按照从小到大输出它所有的质数因子,以空格隔开,最后一个数后面也要有空格。
function primeFactor(intNumber) {
let targetNumber = intNumber;
const result = [];
while (targetNumber > 1) {
let prime = 1;
for (let i = 2; i <= parseInt(Math.sqrt(targetNumber)); i++) {
if (targetNumber % i === 0) {
prime = i;
targetNumber = targetNumber / i;
break;
}
}
if (prime > 1) {
result.push(prime);
} else {
result.push(targetNumber);
targetNumber = 1;
}
}
return result.join(" ") + " ";
}
合并对象 相同键的值
function combineObject(object1, object2) {
const result = {};
for (object1Key in object1) {
if (Object.prototype.hasOwnProperty.call(object1, object1Key)) {
if (object2[object1Key]) {
result[object1Key] = object1[object1Key] + object2[object1Key];
} else {
result[object1Key] = object1[object1Key];
}
}
}
for (object2Key in object2) {
if (Object.prototype.hasOwnProperty.call(object2, object2Key)) {
if (result[object2Key]) {
} else {
result[object2Key] = object2[object2Key];
}
}
}
return result;
}
输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
保证输入的整数最后一位不是0。
按照从右向左的阅读顺序,返回一个不含重复数字的新的整数
输入 9876673
输出 37689
function noRepeatNumber(sourceNum) {
// 变字符串 变数组 反转
const sourceArray = String(sourceNum).split("").reverse();
// set 去重
const reverseSet = new Set(sourceArray);
// set变数组 重新拼接
const result = Number([...reverseSet].join(""));
return result;
}
输出 字符串 中范围在(0~127,包括0和127)字符的种数
输入 abaca
输出 3
function charCodeKinds(sourceStr) {
// 去重
const noRepeat = Array.from(new Set(sourceStr.split("")));
// 过滤
const resultArray = noRepeat.filter((item) => {
const charCodeNumber = item.charCodeAt();
return charCodeNumber >= 0 && charCodeNumber <= 127;
});
return resultArray.length;
}
对数组字符串进行字典排序
其实跟数字排序差不多
存字母字符串是可以比较大小的
function sortString(sourceArray) {
for (let j = 0; j < sourceArray.length; j++) {
let min = sourceArray[j];
for (let i = j; i < sourceArray.length; i++) {
if (sourceArray[i] < min) {
min = sourceArray[i];
sourceArray[i] = sourceArray[j];
sourceArray[j] = min;
}
}
}
return sourceArray;
}
密码
假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。
他是这么变换的,大家都知道手机上的字母: 1–1, abc–2, def–3, ghi–4, jkl–5, mno–6, pqrs–7, tuv–8 wxyz–9, 0–0,就这么简单,渊子把密码中出现的小写字母都变成对应的数字,数字和其他的符号都不做变换,
声明:密码中没有空格,而密码中出现的大写字母则变成小写之后往后移一位,如:X,先变成小写,再往后移一位,不就是y了嘛,简单吧。记住,z往后移是a哦。
输入 YUANzhi1987
输出 zvbo9441987
function passwordTransform(sourcePassword) {
const passwordArray = sourcePassword.split("");
const lowCodeTransform = {
abc: "2",
def: "3",
ghi: "4",
jkl: "5",
mno: "6",
pqrs: "7",
tuv: "8",
wxyz: "9",
};
const resultArray = passwordArray.map((item) => {
let itemResult = item;
const charCodeNum = item.charCodeAt();
if (charCodeNum >= 65 && charCodeNum <= 90) {
// 大写字母转为小写字母向后移动一位
itemResult = String.fromCharCode(charCodeNum + 33);
if (charCodeNum === 90) {
itemResult = "a";
}
} else if (charCodeNum >= 97 && charCodeNum <= 122) {
// 小写字母
for (let key in lowCodeTransform) {
if (key.includes(item)) {
itemResult = lowCodeTransform[key];
}
}
}
return itemResult;
});
找到字符串数组中,这些字符串最长的公共前缀
输入 [“adsp111”, “adspfa”, “adspkiji”]
输出 adsp
如果没有公共前缀,则返回undefined
function returnPrefixString(sourceStrArray) {
const length = sourceStrArray.length;
let min = sourceStrArray[0].length;
let minStr = sourceStrArray[0];
for (let i = 0; i < length; i++) {
if (sourceStrArray[i].length < min) {
min = sourceStrArray[i].length;
minStr = sourceStrArray[i];
}
}
for (let i = minStr.length; i >= 0; i--) {
let key = true;
for (let j = 0; j < length; j++) {
const index = sourceStrArray[j].indexOf(minStr);
if (index !== 0) {
key = false;
}
}
if (key) {
return minStr;
} else {
minStr = minStr.slice(0, i);
}
}
return undefined;
}
对象取值
var object = { ‘a’: [{ ‘b’: { ‘c’: 3 } }] };
_.get(object, ‘a[0].b.c’);
// => 3
_.get(object, [‘a’, ‘0’, ‘b’, ‘c’]);
// => 3
_.get(object, ‘a.b.c’, ‘default’);
// => ‘default’
第一个参数是传入的对象,第二个参数是要取值的path,可能是数组,可能是字符串,第三个参数是未找到路径时,返回的默认参数。
function getValue(sourceObject, source, defaultValue) {
// 是字符串就变成数组
if (typeof source === "string") {
source = source.replace(/\[/g, ".");
source = source.replace(/]/g, "");
source = source.split(".");
}
for (let i = 0; i < source.length; i++) {
if (sourceObject[source[i]] === undefined) {
return defaultValue;
} else {
sourceObject = sourceObject[source[i]];
}
}
return sourceObject;
}
找出字符串中第一个只出现一次的字符
输出第一个只出现一次的字符,如果不存在输出-1
function firstOne(string1) {
const splitString = string1.split('');
const resultObj = {}
let result = -1
for(let i = 0 ; i< splitString.length; i++) {
if (resultObj[splitString[i]]) {
resultObj[splitString[i]] = resultObj[splitString[i]] + 1
} else {
resultObj[splitString[i]] = 1
}
}
console.log(resultObj)
for(let key in resultObj) {
if(resultObj[key] === 1) {
result = key
break
}
}
console.log(result)
return result
}
数字千分位
输入 1000
输出 1,000
如果不足1000,原样返回
通过正则
function thousand(num) {
return (num + "").replace(/\d(?=(\d{3})+$)/g, "$&,");
}
通过数组拆分重组
function thousandNumber(num) {
const strArray = String(num).split("");
if(strArray.length <= 3) {
return num
}
const resultArray3 = [];
for (let i = strArray.length; i >= 0; i = i - 3) {
let start = i - 3;
if (start < 0) {
start = 0;
}
const str3 = strArray.slice(start, i).join('');
resultArray3.push(str3);
}
return resultArray3.reverse().join(",");
}
蛇形矩阵
蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。
例如,当输入5时,应该输出的三角形为:
1 3 6 10 15
2 5 9 14
4 8 13
7 12
11
其实就是找规律 第二行的元素为上一行元素去掉第一个,再减去1即可
function snake(n, upArray) {
if (upArray && n >= 1) {
const nowArray = upArray.map((item) => {
return item - 1;
});
console.log(nowArray);
snake(n - 1, nowArray.slice(1));
} else if(n >= 1){
const nowArray = [1]
for(let i = 1; i<= n; i++) {
nowArray.push(nowArray[i-1] + i + 1)
}
console.log(nowArray)
snake(n - 1, nowArray.slice(1));
} else {
return ''
}
}