JavaScript Algorithms and Data Structures(十)

freeCodeCamp —- JavaScript Algorithms and Data Structures


JavaScript算法和数据结构项目

1. 回文检查器

如果传入的字符串是回文字符串,则返回 true。 否则返回 false

回文 palindrome,指在忽略标点符号、大小写和空格的前提下,正着读和反着读一模一样。

注意检查回文时,你需要先去除所有非字母数字的字符(标点、空格和符号),并将所有字母都转换成大写或都转换成小写。

我们会传入具有不同格式的字符串,如 racecarRaceCar 和 race CAR 等等。

我们也会传入一些包含特殊符号的字符串,例如 2A3*3a22A3 3a22_A3*3#A2

1
2
3
4
5
6
7
8
9
10
11
12
13
function palindrome(str) {
let newStr = str.split(/[\W_]+/gi).join('').toLowerCase();
let len = newStr.length;
console.log(newStr)
for (let i =0;i < len; i++ ){
if( newStr[i] != newStr[len - i - 1]){
return false;
}
}
return true;
}

palindrome("A man, a plan, a canal. Panama");

2. 罗马数字转换器

把传入的数字转为罗马数字。

罗马数字 阿拉伯数字
M 1000
CM 900
D 500
CD 400
C 100
XC 90
L 50
XL 40
X 10
IX 9
V 5
IV 4
I 1

所有罗马数字答案都应该大写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function convertToRoman(num) {
var romanNumerals = [
{value:1000, letter:'M'},
{value:900, letter:'CM'},
{value:500, letter:'D'},
{value:400, letter:'CD'},
{value:100, letter:'C'},
{value:90, letter:'XC'},
{value:50, letter:'L'},
{value:40, letter:'XL'},
{value:10, letter:'X'},
{value:9, letter:'IX'},
{value:5, letter:'V'},
{value:4, letter:'IV'},
{value:1, letter:'I'}
];

var romanNumeral = '';

for (var i = 0; i < romanNumerals.length; i++) {
while (num >= romanNumerals[i].value) {
romanNumeral += romanNumerals[i].letter;
num -= romanNumerals[i].value;
}
}

return romanNumeral;
}

// 示例:将数字 1234 转换为罗马字符
console.log(convertToRoman(1234)); // 输出 MCCXXXIV

3. 恺撒密码

恺撒密码( Caesar cipher)是最简单且最广为人知的密码(ciphers),也被称为移位密码(shift cipher)。 在移位密码中,明文中的字母通过按照一个固定数目进行偏移后被替换成新的字母。

现代最常被应用到的一个变种就是 ROT13 加密,也就是明文中的字母向后移 13 位。 也就是, A ↔ NB ↔ O 等等。

编写一个函数,它将把使用 ROT13 加密编码的字符串作为输入并返回解码字符串。

所有解码后的字母都必须为字母大写。 请不要解码非字母的字符(例如,空格、标点符号),但你需要在结果中保留它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function rot13(str) {
let output = '';
for (let i = 0;i<str.length;i++){
let charCode =str.charCodeAt(i);
if(charCode>=65&&charCode<=90){
output += String.fromCharCode((charCode -65 + 13) % 26 +65);
}else{
output += str.charAt(i)
}
}
return output
}

rot13("SERR PBQR PNZC");

4. 电话号码检查器

如果传入的字符串是一个有效的美国电话号码格式,则返回 true

只要是有效的美国电话号码的格式,用户可以按照他们的方式填写表单中的电话号码。 以下是一些正确的例子(其他格式变形请参考以下例子):

555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555

在这个挑战中,参数可能是 800-692-7753 或者 8oo-six427676;laskdjf 的号码。 你的任务是根据上面不同的格式组合,判断它是否为有效的电话号码。 其中,地区码(电话号码中的前三位)是必须的。 如果提供国家代码,则国家代码只能为 1。 如果传入的参数是有效的美国电话号码就返回 true,否则返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
function telephoneCheck(str) {
// 匹配以上四种格式之一
// ^(1\s?)? 表示匹配国家代码+1(可选),后面可以有一个空格(可选)
// ((\d{3})|\d{3}) 表示匹配区号,可以使用括号,也可以直接使用3个数字
// ([-.\s])? 表示匹配连接符(可选)
// \d{3} 表示匹配3个数字,代表本地号码前半部分
// ([-.\s])? 表示匹配连接符(可选)
// \d{4} 表示匹配4个数字,代表本地号码后半部分
let regex = /^(1\s?)?(\(\d{3}\)|\d{3})([\-\.\s])?\d{3}([\-\.\s])?\d{4}$/;
return regex.test(str);
}

telephoneCheck("555-555-5555");

5. 计算找零

请编写一个用于收银机的函数 checkCashRegister():它的第一个参数为售价 price、第二个参数为支付金额 cash、第三个参数为收银机內的金额 cid

cid 是包含货币面值的二维数组。

函数 checkCashRegister() 应返回含有 status 属性和 change 属性的对象。

如果收银机內的金额少于应找回的零钱数,或者你无法返回确切的数目时,返回 {status: "INSUFFICIENT_FUNDS", change: []}

如果收银机內的金额恰好等于应找回的零钱数,返回 {status: "CLOSED", change: [...]},其中 change 的属性值就是收银机內的金额。

否则,返回 {status: "OPEN", change: [...]},其中 change 键值是应找回的零钱数,并将找零的面值由高到低排序。

货币单位 Unit 面值
Penny 0.01 美元(PENNY)
Nickel 0.05 美元(NICKEL)
Dime 0.1 美元(DIME)
Quarter 0.25 美元(QUARTER)
Dollar 1 美元(ONE)
Five Dollars 5 美元(五)
Ten Dollars 10 美元(TEN)
Twenty Dollars 20 美元(TWENTY)
One-hundred Dollars 100美元(ONE HUNDRED)

下面的抽屉里现金数组示例:

1
2
3
4
5
6
7
8
9
10
11
[
["PENNY", 1.01],
["NICKEL", 2.05],
["DIME", 3.1],
["QUARTER", 4.25],
["ONE", 90],
["FIVE", 55],
["TEN", 20],
["TWENTY", 60],
["ONE HUNDRED", 100]
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function checkCashRegister(price, cash, cid) {
const currencyUnits = [
{ name: "ONE HUNDRED", value: 100.00 },
{ name: "TWENTY", value: 20.00 },
{ name: "TEN", value: 10.00 },
{ name: "FIVE", value: 5.00 },
{ name: "ONE", value: 1.00 },
{ name: "QUARTER", value: 0.25 },
{ name: "DIME", value: 0.10 },
{ name: "NICKEL", value: 0.05 },
{ name: "PENNY", value: 0.01 }
];
//cashAvailable总金额
//reduce() 方法接收的回调函数包含两个参数:total 和 current。total 初始值为 0,用于存储累加的结果,current 包含两个元素,分别是钞票类型和金额。在每次循环中,回调函数将 current 中的第二个元素加上 total,最终返回累加器的当前值。也就是将收银机中每种钞票的金额都加起来,得到收银机中总金额。
let changeDue = cash - price;
let cashAvailable = cid.reduce((total, current) => total + current[1], 0);
let change = [];

if (changeDue > cashAvailable) {
return { status: "INSUFFICIENT_FUNDS", change: [] };
}
// toFixed() 方法将其转换为指定位数的小数
else if (changeDue.toFixed(2) === cashAvailable.toFixed(2)) {
return { status: "CLOSED", change: cid };
} else {
cid = cid.reverse();

for (let i = 0; i < currencyUnits.length; i++) {
let currencyAmount = 0;
while (changeDue >= currencyUnits[i].value && cid[i][1] >= currencyUnits[i].value) {
currencyAmount += currencyUnits[i].value;
cid[i][1] -= currencyUnits[i].value;
changeDue -= currencyUnits[i].value;
changeDue = Math.round(changeDue * 100) / 100;
}
if (currencyAmount > 0) {
change.push([currencyUnits[i].name, currencyAmount]);
}
}
if (changeDue > 0) {
return { status: "INSUFFICIENT_FUNDS", change: [] };
}
return { status: "OPEN", change: change };
}
}

checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]);