文章目录
- HJ16 购物单
- HJ17 坐标移动√
- HJ20 密码验证合格程序√
- HJ24 合唱队√√
- HJ26 字符串排序√√
- HJ27 查找兄弟单词√
- HJ29 字符串加解密√√
- HJ32 密码截取√√
- HJ33 整数与IP地址间的转换√
- HJ36 字符串加密√√
- HJ38 求小球落地5次后所经历的路程和第5次反弹的高度√
- HJ41 称砝码√√
- HJ43 迷宫问题
- HJ45 名字的漂亮度√
- HJ48 从单向链表中删除指定值的节点√
- HJ50 四则运算√
- HJ52 计算字符串的编辑距离
- HJ55 挑7√
- HJ57 高精度整数加法√
- HJ59 找出字符串中第一个只出现一次的字符√
- HJ63 DNA序列√
- HJ64 MP3光标位置
- HJ65 查找两个字符串a,b中的最长公共子串√
- HJ66 配置文件恢复
- HJ67 24点游戏算法
- HJ69 矩阵乘法√
- HJ70 矩阵乘法计算量估算
- HJ71 字符串通配符√
- HJ74 参数解析√
- HJ75 公共子串计算√
- HJ77 火车进站
- HJ82 将真分数分解为埃及分数
- HJ90 合法IP
- HJ92 在字符串中找出连续最长的数字串√
- HJ103 Redraiment的走法√√
- HJ107 求解立方根√
HJ16 购物单
//读取数据处理
let [N, m] = readline().split(" ").map(Number);
//处理数据,使主件的输入一定在附件输入之前
let data = [];
for (let i = 1; i <= m; i++) {
let [v, p, q] = readline().split(" ").map(Number);
data.push([i, v, p, q]);
}
data.sort((a, b) => a[3] - b[3]);
let mains = [],
subparts = [];
let map = {}; //第i行,对应mains的index
for (let i = 0; i < m; i++) {
//处理一条数据
let [index, v, p, q] = data[i];
if (q == 0) {
//主件
mains.push([v / 10, (v / 10) * p]);
map[index] = mains.length - 1;
} else {
//附件
if (!subparts[map[q]]) {
subparts[map[q]] = [];
}
subparts[map[q]].push([v / 10, (v / 10) * p]);
}
}
// 整理数据 w[i][k],v[i][k]
let mLen = mains.length;
let w = new Array(mLen);
let v = new Array(mLen);
for (let i = 0; i < mLen; i++) {
w[i] = [];
v[i] = [];
//w[i][0] 主件
//w[i][1] 主件+附件1
//w[i][2] 主件+附件2
//w[i][3] 主件+附件1+附件2
let subpart = subparts[i];
let subs = subparts[i] ? subparts[i].length : 0;
switch (subs) {
case 2:
w[i][2] = mains[i][0] + subpart[1][0];
v[i][2] = mains[i][1] + subpart[1][1];
w[i][3] = mains[i][0] + subpart[0][0] + subpart[1][0];
v[i][3] = mains[i][1] + subpart[0][1] + subpart[1][1];
case 1:
w[i][1] = mains[i][0] + subpart[0][0];
v[i][1] = mains[i][1] + subpart[0][1];
case 0:
w[i][0] = mains[i][0];
v[i][0] = mains[i][1];
break;
}
}
//背包问题
N = Math.floor(N / 10);
let dp = new Array(N + 1).fill(0);
//初始化
//i=0 没有买东西,满意度为0.初始化dp数组时已经初始化
for (let j = 1; j <= N; j++) {
for (let k = 0; k < w[0].length; k++) {
if (j - w[0][k] >= 0) {
dp[j] = Math.max(dp[j], v[0][k]);
}
}
}
//空间优化
for (let i = 1; i < mLen; i++) {
for (let j = N; j > 0; j--) {
for (let k = 0; k < w[i].length; k++) {
if (j - w[i][k] >= 0) {
dp[j] = Math.max(dp[j], dp[j - w[i][k]] + v[i][k]);
}
}
}
}
console.log(dp[N] * 10);
HJ17 坐标移动√
输入: A10;S20;W10;D30;X;A1A;B10A11;;A10;
输出: 10,-10
输入: ABC;AKL;DA1;
输出: 0,0
let arr = readline().split(";");
let x = 0;
let y = 0;
for (let i = 0; i < arr.length; i++) {
if (/^[ASWD][0-9]{1,2}$/.test(arr[i])) {
let ii = arr[i].slice(0, 1);
let num = Number(arr[i].slice(1));
if (ii === "A") x -= num;
if (ii === "D") x += num;
if (ii === "W") y += num;
if (ii === "S") y -= num;
}
}
console.info(x + "," + y);
HJ20 密码验证合格程序√
密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有长度大于2的不含公共元素的子串重复 (注:其他符号不含空格或换行)
输入:
021Abc9000
021Abc9Abc1
021ABC9000
021$bc9000
输出:
OK
NG
NG
OK
function checkchar(str) {
//包括大小写字母.数字.其它符号,以上四种至少三种
let i0 = 0,
i1 = 0,
i2 = 0,
i3 = 0;
for (let i = 0; i < str.length; i++) {
if (/[a-z]/.test(str[i])) {
i0 = 1;
} else if (/[A-Z]/.test(str[i])) {
i1 = 1;
} else if (/[0-9]/.test(str[i])) {
i2 = 1;
} else {
i3 = 1;
}
}
if (i0 + i1 + i2 + i3 >= 3) {
return true;
} else {
return false;
}
}
function checksubstr(str) {
for (let i = 0; i < str.length - 3; i++) {
let s = str.slice(i, i + 3);
let last = str.slice(i + 3);
if (last.indexOf(s) > -1) return false;
}
return true;
}
let line;
while ((line = readline())) {
if (line.length > 8 && checksubstr(line) && checkchar(line)) {
console.info("OK");
} else {
console.info("NG");
}
}
HJ24 合唱队√√
var num;
while ((num = readline())) {
//186 186 150 200 160 130 197 200
const arr = readline().split(" ").map(Number);
//1,1,1,2,2,1,3,4
let dp1 = handle(arr);
//3,3,2,3,2,1,1,1
let dp2 = handle(arr.reverse()).reverse();
let max = 0;
for (let i = 0; i < dp1.length; i++) {
max = Math.max(max, dp1[i] + dp2[i] - 1);
}
console.log(arr.length - max);
}
function handle(arr) {
const dp = [];
for (let i = 0; i < arr.length; i++) {
dp[i] = 1;
for (let j = 0; j < i; j++) {
if (arr[j] < arr[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return dp;
}
HJ26 字符串排序√√
编写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
输入:
A Famous Saying: Much Ado About Nothing (2012/8).
输出:
A aaAAbc dFgghh: iimM nNn oooos Sttuuuy (2012/8).
let res = "";
let arr = readline().split("");
let sorted = [];
for (let i = 0; i < 26; i++) {
for (let j = 0; j < arr.length; j++) {
// 为大写字母或小写字母(从A~Z或a~z排序)
if (arr[j].charCodeAt(0) == 65 + i || arr[j].charCodeAt(0) == 97 + i) {
sorted.push(arr[j]);
}
}
}
for (let i = 0; i < arr.length; i++) {
if (!/[A-Za-z]/g.test(arr[i])) {
sorted.splice(i, 0, arr[i]);
}
}
console.log(sorted.join(""));
HJ27 查找兄弟单词√
定义一个单词的“兄弟单词”为:交换该单词字母顺序(注:可以交换任意次),而不添加、删除、修改原有的字母就能生成的单词。
兄弟单词要求和原来的单词不同。例如: ab 和 ba 是兄弟单词。 ab 和 ab 则不是兄弟单词。
现在给定你 n 个单词,另外再给你一个单词 x ,让你寻找 x 的兄弟单词里,按字典序排列后的第 k 个单词是什么?
注意:字典中可能有重复单词。
输入描述:
输入只有一行。 先输入字典中单词的个数n,再输入n个单词作为字典单词。 然后输入一个单词x 最后后输入一个整数k
输出描述:
第一行输出查找到x的兄弟单词的个数m 第二行输出查找到的按照字典顺序排序后的第k个兄弟单词,没有符合第k个的话则不用输出。
示例1
输入: 3 abc bca cab abc 1
输出:
2
bca
示例2
输入: 6 cab ad abcd cba abc bca abc 1
输出:
3
bca
说明:
abc的兄弟单词有cab cba bca,所以输出3
经字典序排列后,变为bca cab cba,所以第1个字典序兄弟单词为bca
// 排序后相同,排序前不相同,则为兄弟单词
let ls = readline().split(" ");
let lastTwo = ls.slice(-2);
let word = lastTwo[0];
let index = lastTwo[1];
let cc = Number(ls[0]);
let lsn = [];
for (let i = 1; i < cc + 1; i++) {
if (
word.split("").sort().join("") === ls[i].split("").sort().join("") &&
word !== ls[i]
) {
lsn.push(ls[i]);
}
}
lsn.sort();
console.info(lsn.length);
console.info(lsn[index - 1] ? lsn[index - 1] : "");
HJ29 字符串加解密√√
加密方法为:
当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;
当内容是数字时则把该数字加1,如0替换1,1替换2,9替换0;
其他字符不做变化。
解密方法为加密的逆过程。
输入:
abcdefg
BCDEFGH
输出:
BCDEFGH
abcdefg
let str;
while ((str = readline())) {
let encryption = [];
let decryption = [];
//加密
str.split("").forEach((item, index) => {
if (/[A-Z]/.test(item)) {
//大写
if (item === "Z") {
encryption.push("a");
} else {
encryption.push(String.fromCharCode(item.charCodeAt(0) + 33));
}
} else if (/[a-z]/.test(item)) {
//小写
if (item === "z") {
encryption.push("A");
} else {
encryption.push(String.fromCharCode(item.charCodeAt(0) - 31));
}
} else if (/[0-9]/.test(item)) {
//数字
if (item === "9") {
encryption.push(0);
} else {
encryption.push(++item);
}
}
});
console.log(encryption.join(""));
//解密
str = readline();
str.split("").forEach((item, index) => {
if (/[A-Z]/.test(item)) {
if (item === "A") {
decryption.push("z");
} else {
decryption.push(String.fromCharCode(item.charCodeAt(0) + 31));
}
}
if (/[a-z]/.test(item)) {
if (item === "a") {
decryption.push("Z");
} else {
decryption.push(String.fromCharCode(item.charCodeAt(0) - 33));
}
}
if (/[0-9]/.test(item)) {
//数字
if (item === "0") {
decryption.push(9);
} else {
decryption.push(--item);
}
}
});
console.log(decryption.join(""));
}
HJ32 密码截取√√
示例1
输入:ABBA
输出:4
示例2
输入:ABBBA
输出:5
示例3
输入:12HHHHA
输出:4
// 密码截取
function getStringLength(key) {
let maxLength = 0;
let len = key.length;
for (let i = 0; i < len; i++) {
// 第一种情况 ABBA
var low = i; // 左指针
var high = i + 1; // 右指针
// 相等但无越界
while (low >= 0 && high < len && key[low] == key[high]) {
low--;
high++;
}
maxLength = Math.max(maxLength, high - low - 1);
// 第二种情况 ABBBA
low = i; // 左指针
high = i + 2; // 右指针
while (low >= 0 && high < len && key[low] == key[high]) {
low--;
high++;
}
maxLength = Math.max(maxLength, high - low - 1);
}
console.log(maxLength);
}
var line = readline();
getStringLength(line);
HJ33 整数与IP地址间的转换√
原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成
一个长整数。
举例:一个ip地址为10.0.3.193
每段数字 相对应的二进制数
10 00001010
0 00000000
3 00000011
193 11000001
组合起来即为:00001010 00000000 00000011 11000001,转换为10进制数就是:167773121,即该IP地址转换后的数字就是它了。
输入:
10.0.3.193
167969729
输出:
167773121
10.3.3.193
let ip = readline()
.split(".")
.map((item) => Number(item));
let ten = Number(readline());
let ipStr = "";
for (let i = 0; i < ip.length; i++) {
ipStr += ("00000000" + ip[i].toString(2)).slice(-8);
}
console.info(parseInt(ipStr, 2));
let tenStr = ten.toString(2);
let result2 = [];
while (tenStr.length > 8) {
result2.unshift(parseInt(tenStr.slice(-8), 2));
tenStr = tenStr.slice(0, tenStr.length - 8);
}
result2.unshift(parseInt(tenStr, 2));
console.info(result2.join("."));
HJ36 字符串加密√√
有一种技巧可以对数据进行加密,它使用一个单词作为它的密匙。下面是它的工作原理:首先,选择一个单词作为密匙,如TRAILBLAZERS。如果单词中包含有重复的字母,只保留第1个,将所得结果作为新字母表开头,并将新建立的字母表中未出现的字母按照正常字母表顺序加入新字母表。如下所示:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S C D F G H J K M N O P Q U V W X Y (实际需建立小写字母的字母表,此字母表仅为方便演示)
上面其他用字母表中剩余的字母填充完整。在对信息进行加密时,信息中的每个字母被固定于顶上那行,并用下面那行的对应字母一一取代原文的字母(字母字符的大小写状态应该保留)。因此,使用这个密匙, Attack AT DAWN (黎明时攻击)就会被加密为Tpptad TP ITVH。
请实现下述接口,通过指定的密匙和明文得到密文。
输入描述:
先输入key和要加密的字符串
输出描述:
返回加密后的字符串
示例1
输入:
nihao
ni
输出:
le
let keys = readline().toLowerCase().split("");
let target = readline().split("");
keys = [...new Set(keys)];
let theMap = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
];
//先把密钥添加进去,再把剩下的字符添加进去形成完整的密钥;
for (let i = 0; i < 26; i++) {
if (!keys.includes(theMap[i])) {
keys.push(theMap[i]);
}
}
let res = "";
for (let item of target) {
if (/[A-Z]/.test(item)) {
res += keys[theMap.indexOf(item.toLowerCase())].toUpperCase();
} else {
res += keys[theMap.indexOf(item)];
}
}
console.info(res);
HJ38 求小球落地5次后所经历的路程和第5次反弹的高度√
假设一个球从任意高度自由落下,每次落地后反跳回原高度的一半; 再落下, 求它在第5次落地时,共经历多少米?第5次反弹多高?
输入描述:
输入起始高度,int型
输出描述:
分别输出第5次落地时,共经过多少米以及第5次反弹多高。
注意:你可以认为你输出保留六位或以上小数的结果可以通过此题。
示例1
输入:
1
输出:
2.875
0.03125
let height = Number(readline());
let len = 0;
let last = 0;
for (let i = 0; i < 5; i++) { // 共5次反弹
// 计算反弹一次总高度(完整+一半)
len += height + Number(Math.round((height / 2) * 100000) / 100000);
// 计算反弹一次后现有高度
height = Number(Math.round((height / 2) * 100000) / 100000);
}
console.info(len - height);
console.info(height);
HJ41 称砝码√√
输入描述:
对于每组测试数据:
第一行:n — 砝码的种数(范围[1,10])
第二行:m1 m2 m3 … mn — 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 … xn — 每种砝码对应的数量(范围[1,10])
输出描述:
利用给定的砝码可以称出的不同的重量数
输入:
2
1 2
2 1
输出:
5
说明:
可以表示出0,1,2,3,4五种重量。
let n;
while ((n = readline())) {
let weight = readline().split(" ").map(Number);
let num = readline().split(" ").map(Number);
let res = [0];
for (let i = 0; i < weight.length; i++) {
let current = [...res];
for (let j = 1; j <= num[i]; j++) {
current.forEach((item) => {
let val = item + j * weight[i];
res.push(val);
});
}
res = [...new Set(res)];
}
console.info(res.length);
}
HJ43 迷宫问题
while ((line = readline())) {
const [m, n] = line.split(" ").map((item) => item - 0);
const arr = [];
for (let i = 0; i < m; i++) {
arr.push(
readline()
.split(" ")
.map((item) => item - 0)
);
}
// 1 表示走过,0 表示没走过
const map = new Array(m).fill().map(() => new Array(n).fill(0));
// 保存路线的队列
const queue = [];
// 上下左右四个移动方向
const flag = [
[0, 1],
[1, 0],
[0, -1],
[-1, 0],
];
let over = false;
const dp = (i, j) => {
// 标记当前已经通过了
if (over) return;
// 走到最后位置了
if (i === m - 1 && j == n - 1) {
over = true;
queue.push([i, j]);
return true;
}
// 坐标出边界、碰到墙了、之前走过(说明之前没走通) 直接返回函数,后面不用走了
if (i < 0 || j < 0 || i == m || j == n || arr[i][j] || map[i][j]) {
return false;
}
// 走过,后面碰到都不用走了
map[i][j] = 1;
for (let index = 0; index < 4; index++) {
// 将当前坐标保存到路线队列中
queue.push([i, j]);
dp(i + flag[index][0], j + flag[index][1]);
if (over) break;
// 回溯
queue.pop();
}
};
dp(0, 0);
queue.forEach((item) => {
console.log(`(${item[0]},${item[1]})`);
});
}
HJ45 名字的漂亮度√
每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个不同字母拥有相同的“漂亮度”。字母忽略大小写。
给出多个字符串,计算每个字符串最大可能的“漂亮度”。
输入:
2
zhangsan
lisi
输出:
192
101
说明:
对于样例lisi,让i的漂亮度为26,l的漂亮度为25,s的漂亮度为24,lisi的漂亮度为25+26+24+26=101.
function counts(str) {
let m = str.split("");
let theMap = {};
for (let i = 0; i < m.length; i++) {
theMap[m[i]] ? theMap[m[i]]++ : (theMap[m[i]] = 1);
}
return theMap;
}
let n = Number(readline());
while (n > 0) {
let theMap = counts(readline());
let ii = Object.values(theMap).sort((a, b) => b - a);
let res = 0;
for (let j = 0; j < ii.length; j++) {
res += ii[j] * (26 - j);
}
console.info(res);
n--;
}
HJ48 从单向链表中删除指定值的节点√
构造过程,例如输入一行数据为:
6 2 1 2 3 2 5 1 4 5 7 2 2
则第一个参数6表示输入总共6个节点,第二个参数2表示头节点值为2,剩下的2个一组表示第2个节点值后面插入第1个节点值,为以下表示:
1 2 表示为
2->1
链表为2->1
3 2表示为
2->3
链表为2->3->1
5 1表示为
1->5
链表为2->3->1->5
4 5表示为
5->4
链表为2->3->1->5->4
7 2表示为
2->7
链表为2->7->3->1->5->4
最后的链表的顺序为 2 7 3 1 5 4
最后一个参数为2,表示要删掉节点为2的值
删除 结点 2
则结果为 7 3 1 5 4
输入: 5 2 3 2 4 3 5 2 1 4 3
输出: 2 5 4 1
说明:
形成的链表为2->5->3->4->1
删掉节点3,返回的就是2->5->4->1
示例2
输入: 6 2 1 2 3 2 5 1 4 5 7 2 2
输出: 7 3 1 5 4
let [total, start, ...arr] = readline().split(" ").map(Number);
const rmVal = arr.pop();
let res = [start];
for (let i = 0; i < arr.length; i += 2) {
const val = arr[i];
const head = arr[i + 1];
const index = res.indexOf(head);
res.splice(index + 1, 0, val);
}
print(res.filter((n) => n !== rmVal).join(" "));
HJ50 四则运算√
输入一个表达式(用字符串表示),求这个表达式的值。
保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。
输入: 3+2{1+2*[-4/(8-6)+7]}
输出: 25
function cal(str) {
let newLine = str.replace(/(\{|\[)/ig,'(').replace(/(\}|\])/ig,')');
console.log(eval(newLine));
}
let line;
while ((line = readline())) {
cal(line);
}
HJ52 计算字符串的编辑距离
Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。编辑距离的算法是首先由俄国科学家 Levenshtein 提出的,故又叫 Levenshtein Distance 。
例如:
字符串A: abcdefg
字符串B: abcdef
通过增加或是删掉字符 ”g” 的方式达到目的。这两种方案都需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。
要求:
给定任意两个字符串,写出一个算法计算它们的编辑距离。
输入:
abcdefg
abcdef
输出:
1
function minDistance(word1, word2) {
let len1 = word1.length;
let len2 = word2.length;
let dp = Array(len1 + 1)
.fill()
.map((item) => Array(len2 + 1).fill(0)); //dp数组
for (let i = 1; i <= len1; i++) dp[i][0] = i;
for (let j = 1; j <= len2; j++) dp[0][j] = j;
// for (let i = 0; i < dp.length; i++) {
// console.info(dp[i]);
// }
for (let i = 1; i <= len1; i++) {
for (let j = 1; j <= len2; j++) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(
dp[i - 1][j] + 1, //插入
dp[i][j - 1] + 1, //删除
dp[i - 1][j - 1] + 1 //替换
);
}
}
}
// for (let i = 0; i < dp.length; i++) {
// console.info(dp[i]);
// }
return dp[len1][len2];
}
let line;
while ((line = readline())) {
console.info(minDistance(line, readline()));
}
HJ55 挑7√
输出 1到n之间 的与 7 有关数字的个数。
一个数与7有关是指这个数是 7 的倍数,或者是包含 7 的数字(如 17 ,27 ,37 … 70 ,71 ,72 ,73…)
输入:
20
输出:
3
说明:
输入20,1到20之间有关的数字包括7,14,17共3个。
function getSevenCount() {
if (Number(line) < 7) return 0;
let res = 0;
for (let i = 7; i <= Number(line); i++) {
if (i % 7 === 0 || i.toString().split("").includes("7")) {
res++;
}
}
return res;
}
let line;
while ((line = readline())) {
console.info(getSevenCount(line));
}
HJ57 高精度整数加法√
输入:
9876543210
1234567890
输出:
11111111100
// 我们将两个字符串从尾到头进行处理
// 逐位相加,保留个位数字到结果字符串中,并记录进位的值在下一次循环中再次逐位相加
// 最终输出结果字符串
function sumBig(str1, str2) {
const a = str1.split("");
const b = str2.split("");
let c = 0;
let res = "";
while (a.length || b.length || c) {
c += ~~a.pop() + ~~b.pop(); // 个位求和
res = (c % 10) + res; // 记录
c = c > 9 ? 1 : 0; // 是否有进位
}
return res;
}
console.log(sumBig(readline(), readline()));
HJ59 找出字符串中第一个只出现一次的字符√
输入:
asdfasdfo
输出:
o
let n = readline().split("");
let m = {};
for (let i = 0; i < n.length; i++) {
m[n[i]] ? m[n[i]]++ : (m[n[i]] = 1);
}
let res = -1;
for (let item in m) {
if (m[item] === 1) {
res = item;
break;
}
}
console.info(res);
HJ63 DNA序列√
输入:
ACGT
2
输出:
CG
说明:
ACGT长度为2的子串有AC,CG,GT3个,其中AC和GT2个的GC-Ratio都为0.5,CG为1,故输出CG
示例2
输入:
AACTGTGCACGACCTGA
5
输出:
GCACG
说明:
虽然CGACC的GC-Ratio也是最高,但它是从左往右找到的GC-Ratio最高的第2个子串,所以只能输出GCACG。
const line = readline();
const n = Number(readline());
const l = line.length;
let max = 0; // 最大出现数量(比例)
let result; // 输出的子串
for (let i = 0; i <= l - n; i++) {
const cut = line.slice(i, i + n); // 根据长度截取的子串
let timer = 0; // 初始化 GC 出现次数
for (let j of cut) {
if (j === "G" || j === "C") {
timer++;
}
}
if (timer > max) {
result = cut; // 更新输出的子串
max = timer; // 更新最大数量(比例)
}
}
console.log(result);
HJ64 MP3光标位置
输入描述:
输入说明:
1 输入歌曲数量
2 输入命令 U或者D
输出描述:
输出说明
1 输出当前列表
2 输出当前选中歌曲
示例1
输入:
10
UUUU
输出:
7 8 9 10
7
let n = Number(readline());
let index = 0; //光标所在位置
let start = 0; //显示起始坐标
let control = readline();
let l = []; //生成歌曲列表
for (let i = 1; i <= n; i++) {
l.push(i);
}
for (let x of control) {
//解析每个控制命令来做出相应处理
if (x == "U") {
//如果命令是‘U’
if (index === 0) {
//在光标起始位置为0的情况下
index += -1 + n; //光标移到最后一首歌曲
start = n - 4; //起始显示坐标变为总长度-4
} else {
index += -1; //其他光标坐标-1
if (index < start) {
//如果光标坐标小于起始显示坐标
start = index; //那么让起始显示坐标=光标坐标
}
}
}
if (x == "D") {
//如果命令是‘U’
if (index == n - 1) {
//在光标起始位置为最后一首歌的情况下
index = 0; //光标移到第一首歌
start = 0; //起始显示坐标移到第一首歌
} else {
index += 1; //光标下移一首歌
if (index > start + 3) {
//如果光标下移后坐标大于显示的最后一首歌的坐标
start += 1; //那么让起始显示坐标+1
}
}
}
}
if (n <= 4) {
//如果长度小于4,则直接打印所有歌
console.info(l.join(" "));
} else {
//如果长度大于4,则打印起始坐标开始到起始坐标+4的歌单
console.info(l.slice(start, start + 4).join(" "));
}
console.info(l[index]); //打印当前歌曲
HJ65 查找两个字符串a,b中的最长公共子串√
输入:
abcdefghijklmnop
abcsafjklmnopqrstuvw
输出:
jklmnop
// 总体思路:从短的字符串中取子串,看其在长字符串中是否存在
let s1 = readline();
let s2 = readline();
if (s1.length > s2.length) {
[s1, s2] = [s2, s1];
}
let length = 0;
let res = "";
for (let i = 0; i < s1.length; i++) {
for (let j = i + 1; j <= s1.length; j++) {
let sub = s1.slice(i, j);
if (s2.includes(sub)) {
if (j - i > length) {
res = sub;
length = j - i;
}
} else {
break;
}
}
}
console.info(res);
HJ66 配置文件恢复
let line;
while ((line = readline())) {
let strs = line.split(" ");
let result;
if (strs.length === 1) {
if ("reset".indexOf(strs[0]) === 0) {
print("reset what");
} else {
print("unknown command");
}
}
if (strs.length === 2) {
let cmd1 = ["reset", "board", "board", "reboot", "backplane"];
let cmd2 = ["board", "add", "delete", "backplane", "abort"];
let results = [
"board fault",
"where to add",
"no board at all",
"impossible",
"install first",
];
let matched = [];
for (let i = 0; i < cmd1.length; i++) {
if (cmd1[i].indexOf(strs[0])===0) {
matched.push(i);
}
}
if (matched.length === 0) {
result = "unknown command";
} else if (matched.length > 0) {
let count = 0;
for (let num of matched) {
if (cmd2[num].indexOf(strs[1])===0) {
result = results[num];
count++;
}
}
if (count !== 1) {
result = "unknown command";
}
}
print(result);
}
}
HJ67 24点游戏算法
//类似深度搜索
let status;
while ((line = readline())) {
let arr = line.split(" ").map((x) => parseInt(x));
status = false;
dfs(-1, 0, arr, status);
print(status);
}
function dfs(step, pre, arr) {
if (step == 3) {
if (pre == 24) {
status = true;
return;
}
} else {
step++;
for (let key in arr) {
let newArr = JSON.parse(JSON.stringify(arr));
let num = newArr.splice(key, 1)[0];
dfs(step, pre + num, newArr);
dfs(step, pre - num, newArr);
dfs(step, pre * num, newArr);
dfs(step, pre / num, newArr);
}
return;
}
}
HJ69 矩阵乘法√
输入:
2
3
2
1 2 3
3 2 1
1 2
2 1
3 3
输出:
14 13
10 11
let line;
while ((line = readline())) {
let x = Number(line);
let y = Number(readline());
let z = Number(readline());
let A = [];
let B = [];
for (let i = 0; i < x; i++) {
let row = readline().trim().split(" ").map(Number);
A.push(row);
}
for (let i = 0; i < y; i++) {
let row = readline().trim().split(" ").map(Number);
B.push(row);
}
// 初始化一个二维数组,初始值为0
let R = Array(x)
.fill(null)
.map(() => Array(z).fill(0));
for (let i = 0; i < x; i++) {
for (let k = 0; k < z; k++) {
for (let j = 0; j < y; j++) {
// 计算每个输出单元格的数据,A行与B列的乘积,长度为y
R[i][k] += A[i][j] * B[j][k];
}
}
}
// 按行输出
for (let i = 0; i < x; i++) {
console.info(R[i].join(" "));
}
}
HJ70 矩阵乘法计算量估算
输入:
3
50 10
10 20
20 5
(A(BC))
输出:
3500
let n = Number(readline());
let arr = [];
let order = [];
let res = 0;
// 处理输入的矩阵行列数据
for (let i = 0; i < n; i++) {
arr.push(readline().split(" "));
}
let f = readline().split("");
// 1、字符 是左括号,什么也不做
// 2、字符 是右括号,出栈
// 3、字符 是非括号,入栈
for (let i = 0; i < f.length; i++) {
if (/[A-Z]/.test(f[i])) {
order.unshift(arr[f[i].charCodeAt(0) - 65]);
} else if (f[i] === ")" && order.length >= 2) {
let b = order.shift();
let a = order.shift();
// [m,n] x [n,p],共会有n*p*m次乘法运算
// 如果是(A(BC)),计算BC
res += a[1] * b[1] * a[0];
// 将BC结果压入栈
order.unshift([a[0], b[1]]);
}
}
console.info(res);
HJ71 字符串通配符√
实现如下2个通配符:
:匹配0个或以上的字符(注:能被和?匹配的字符仅由英文字母和数字0到9组成,下同)
?:匹配1个字符
注意:匹配时不区分大小写。
输入描述:
先输入一个带有通配符的字符串,再输入一个需要匹配的字符串
输出描述:
返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false
示例1
输入:
te?t*.*
txt12.xls
输出:
false
while ((line1 = readline())) {
var line2 = readline();
var regStr = line1
.toLowerCase()
.replace(/\?/g, "[a-z0-9]")
.replace(/\./g, ".")
.replace(/\*/g, "[a-z0-9]*");
var reg = new RegExp("^" + regStr + "$", "ig");
print(reg.test(line2));
}
HJ74 参数解析√
解析规则:
1.参数分隔符为空格
2.对于用""包含起来的参数,如果中间有空格,不能解析为多个参数。比如在命令行输入xcopy /s “C:\program files” "d:“时,参数仍然是4个,第3个参数应该是字符串C:\program files,而不是C:\program,注意输出参数时,需要将”"去掉,引号不存在嵌套情况。
输入:
xcopy /s c:\ d:\e
输出:
4
xcopy
/s
c:\
d:\e
let str1 = readline().replace(/[' ']/g, "\n");
let e = "";
let flag = false;
for (let i = 0; i < str1.length; i++) {
if (str1[i] === '"') {
flag = !flag;
} else if (flag && str1[i] == "\n") {
e += " ";
} else {
e += str1[i];
}
}
console.info(e.split("\n").length);
console.info(e);
HJ75 公共子串计算√
给定两个只包含小写字母的字符串,计算两个字符串的最大公共子串的长度。
注:子串的定义指一个字符串删掉其部分前缀和后缀(也可以不删)后形成的字符串。
输入:
asdfas
werasdfaswer
输出:
6
let str1 = readline();
let str2 = readline();
if (str1.length > str2.length) {
[str1, str2] = [str2, str1];
}
let max = 0;
for (let i = 0; i < str1.length; i++) {
for (let j = i + 1; j <= str1.length; j++) {
let s = str1.slice(i, j);
if (str2.indexOf(s) > -1) {
max = Math.max(max, s.length);
}
}
}
console.info(max);
HJ77 火车进站
输入:
3
1 2 3
输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
说明:
第一种方案:1进、1出、2进、2出、3进、3出
第二种方案:1进、1出、2进、3进、3出、2出
第三种方案:1进、2进、2出、1出、3进、3出
第四种方案:1进、2进、2出、3进、3出、1出
第五种方案:1进、2进、3进、3出、2出、1出
请注意,[3,1,2]这个序列是不可能实现的。
const number = parseInt(readline());
const trains = readline().split(" ");
const paths = [];
function sortAll(vals = [], max = 0, inStack = [], outStack = []) {
//已经全部出站
if (outStack.length === max) {
paths.push(outStack.join(" "));
return;
}
// 一个都没进站,只能进站
if (vals.length === max) {
inStack.push(vals.shift());
sortAll(vals, max, inStack, outStack);
return;
}
// 还有可以进站的,选择进站
if (vals.length > 0) {
const cur = vals.shift();
inStack.push(cur);
sortAll(vals, max, inStack, outStack);
inStack.pop();
vals.unshift(cur);
}
// 有可以出战的,选择出战
if (inStack.length > 0) {
const cur = inStack.pop();
outStack.push(cur);
sortAll(vals, max, inStack, outStack);
outStack.pop();
inStack.push(cur);
}
}
sortAll(trains, number);
paths.sort((l, r) => {
let p = 0;
while (p < l.length) {
if (l[p] < r[p]) {
return -1;
} else if (l[p] > r[p]) {
return 1;
}
p++;
}
});
paths.forEach((item) => console.log(item));
HJ82 将真分数分解为埃及分数
let line;
const getCommonConvention = (x, y) => {
// 求最小公约数 欧里几德算法,辗转相除法
if (y == 0) {
return x;
}
let z = x % y;
return getCommonConvention(y, z);
};
const getCommonMultiple = (x, y) => {
// 求最小公倍数
return (x * y) / getCommonConvention(x, y);
};
const getCalc = (x, y) => {
// 存放结果集合
let result = [];
let increase = 0;
while (increase != 1) {
// 分母处以分子判断分子是分母的几分之几。比如8/11。 11/8 大于1 小于2 所以最多占1/2
let a = Math.floor(y / x);
// 获取 2和11的最小倍数22 转变成相同分母
let commonMultiple = getCommonMultiple(y, a + 1);
// 将1/2放入第一个集合
result.push("1/" + String(a + 1));
// 同等放大然后计算剩下的分子
increase = (commonMultiple / y) * x - commonMultiple / (a + 1);
// 比如 8 / 11 a=1 a+1 = 2. 第一个是1/2 所以最小公倍数是22, (22/11 * 8) - (22/1+1) 就是余数 5。
// 简单来说就是。8/11 - 1/2 转变成 16/22 - 11/22 剩余5 即是5/22
// 将问题转变成1/2 + 5/22的埃及分数 我们只需要求5/22的埃及分数
// 判断剩余的值 和 最小公倍数是不是可以整除 如果整除则代表分子是分母的 1/xx.
// 如果不能整除则继续寻找 5/22的埃及分数
if (y % x == 0) {
y = commonMultiple / increase;
x = 1;
} else {
x = increase;
y = commonMultiple;
}
if (increase == 1) {
result.push("1/" + String(commonMultiple));
}
}
return result;
};
while ((line = readline())) {
let str = line;
let numArr = str.split("/");
let x = parseInt(numArr[0]);
let y = parseInt(numArr[1]);
let result = getCalc(x, y);
console.log(result.join("+"));
}
HJ90 合法IP
while ((str = readline())) {
let strArr = str.split(".");
let res = "YES";
//ipv4 不能大于255不能小于0;
//多个字符不能以0开头,只有一个字符可以是0
//每个字符不能是除0~9以外的字符
if (strArr.length !== 4) {
res = "NO";
} else {
for (let i = 0; i < strArr.length; i++) {
let el = strArr[i];
if (!el || Number(el) > 255 || Number(el) < 0) {
//每一项不能小于0或大于255
res = "NO";
break;
} else {
//遍历每一个字符
for (let s = 0; s < el.length; s++) {
let f = el.charCodeAt(s);
//多个数字,以0开头不行
if ((s == 0 && el[s] == 0 && el.length > 1) || f < 48 || f > 57) {
res = "NO";
break;
}
}
}
}
}
console.log(res);
}
HJ92 在字符串中找出连续最长的数字串√
输入一个字符串,返回其最长的数字子串,以及其长度。若有多个最长的数字子串,则将它们全部输出(按原字符串的相对位置)
输入:
abcd12345ed125ss123058789
a8a72a6a5yy98y65ee1r2
输出:
123058789,9
729865,2
说明:
样例一最长的数字子串为123058789,长度为9
样例二最长的数字子串有72,98,65,长度都为2
let line;
while ((line = readline())) {
let str = line
.replace(/[^0-9]/g, " ")
.split(" ")
.filter((item) => item !== "");
let newStr = [...str];
newStr.sort((a, b) => Number(b) - Number(a));
let maxLen = newStr[0].length;
let res = "";
for (let i = 0; i < str.length; i++) {
if (str[i].length === maxLen) {
res += str[i];
}
}
console.info(res + "," + maxLen);
}
HJ103 Redraiment的走法√√
输入:
6
2 5 1 5 4 5
输出:
3
说明:
6个点的高度各为 2 5 1 5 4 5
如从第1格开始走,最多为3步, 2 4 5 ,下标分别是 1 5 6
从第2格开始走,最多只有1步,5
而从第3格开始走最多有3步,1 4 5, 下标分别是 3 5 6
从第5格开始走最多有2步,4 5, 下标分别是 5 6
所以这个结果是3。
let line;
while ((line = readline())) {
let n = Number(line);
let list = readline().split(" ").map(Number);
let result = new Array(n).fill(1);
let maxLen = 1;
for (var i = 0; i < n; i++) {
for (var j = 0; j < i; j++) {
if (list[i] > list[j]) {
result[i] = Math.max(result[i], result[j] + 1);
}
}
}
maxLen = Math.max(maxLen, ...result);
console.log(maxLen);
}
HJ107 求解立方根√
计算一个浮点数的立方根,不使用库函数。
保留一位小数。
示例1
输入:
19.9
输出:
2.7
示例2
输入:
2.7
输出:
1.4
let n = Number(readline());
let res = 0;
let flag = true; //是正数吗
if (n < 0) {
n = -n;
flag = false;
}
while (res * res * res <= n) {
res += 0.01;
}
if (flag) {
console.info(res.toFixed(1));
} else {
console.info(-res.toFixed(1));
}
这篇博客记录了作者在牛客网上完成的中等级前端题目,包括坐标移动、密码验证、字符串排序、字符串加密等多个挑战。文章详细介绍了每个问题的解决思路和规则,涉及字符串操作、算法和逻辑判断等知识点,适合前端开发者学习和练习。
&spm=1001.2101.3001.5002&articleId=124462302&d=1&t=3&u=9723413510684807a05ab313761d7170)
766

被折叠的 条评论
为什么被折叠?



