本篇都是在刷题的时候自己做的部分题解答案记录,非官方题解,如有不足,请见谅😂

下划线转驼峰

描述:要求输入任意层级的一个object对象,对key值进行处理,把下划线分隔的key改为驼峰式的key(doSomething),最后输出这个对象
// 下划线转驼峰
const toCamel = (key) => {
  // sddf_ssd
  return key.replaceAll(/_+\w/g, (m) => {
    return m.replaceAll("_", "").toUpperCase();
  });
};

const obj = {
  name_lo: "aa",
  stamk_god: "333",
  probs_dog_good: {
    yes_mama: 11,
  },
};
const doJson = (obj) => {
  for (let key in obj) {
    obj[toCamel(key)] = obj[key];
    delete obj[key];
    if (
      Object.prototype.toString.call(obj[toCamel(key)]) ===
      Object.prototype.toString()
    ) {
      doJson(obj[toCamel(key)]);
    }
  }
  return obj;
};

console.log(toCamel("name_longly_sex"), doJson(obj));

最长公共子串

描述:查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!
1≤length≤300
输入描述:输入两个字符串
输出描述:返回重复出现的字符
示例1
输入:
abcdefghijklmnop
abcsafjklmnopqrstuvw
输出:
jklmnop
/**
 * 查找两个字符串a,b中的最长公共子串
 */
let str1 = "1AB2345CD";
let str2 = "12345EF";
let samestr = "";
const maxlenstr = str1.length > str2.length ? str1 : str2; //较长的字符串
const minstr = str1.length > str2.length ? str2 : str1; //较短

for (let i = 0; i < minstr.length; i++) {
  let tempstr = "";
  for (let j = i + 1; j <= minstr.length; j++) {
    //对每个字符相邻直到末尾的所有子串进行对比
    tempstr = minstr.slice(i, j); //剪出相邻的子串
    if (tempstr.length < samestr.length) {
      //如果子串短于当前存储的最长串则跳过
      continue;
    }
    if (maxlenstr.indexOf(tempstr) > -1 && samestr.length < tempstr.length) {
      //与长的字符串匹配,且大于存储的最长串就覆盖
      samestr = tempstr;
    }
  }
}
console.log(samestr);

密码验证合格程序

描述:
密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有长度大于2的包含公共元素的子串重复 (注:其他符号不含空格或换行)
1≤n≤100
输入描述:
一组字符串。
输出描述:
如果符合要求输出:OK,否则输出NG
/**
 *  密码验证合格程序
 */
  const pwd = "123344444";
  if (pwd.length <= 8) {
    return console.log("NG");
  }
  let ruleCount = 0;
  if (/[a-z]/g.test(pwd)) {
    ruleCount++;
  }
  if (/[A-Z]/g.test(pwd)) {
    ruleCount++;
  }
  if (/\d/g.test(pwd)) {
    ruleCount++;
  }
  if (/\W/g.test(pwd)) {
    ruleCount++;
  }
  if (ruleCount < 3) {
    return console.log("NG");
  }

  for (let i = 0; i < pwd.length; i++) {
    for (let j = i + 3; j <= pwd.length; j++) {
      const str = pwd.slice(i, j);
      if (pwd.lastIndexOf(str) > -1 && pwd.lastIndexOf(str) != i) {
        return console.log("NG");
      }
    }
  }
  console.log("OK");

VLAN资源池

描述:VLAN是一种对局域网设备进行逻辑划分的技术,为了标识不同的VLAN,引入VLAN ID(1-4094之间的整数)的概念。定义一个VLAN ID的资源池(下称VLAN资源池),资源池中连续的VLAN用开始VLAN-结束VLAN表示,不连续的用单个整数表示,所有的VLAN用英文逗号连接起来。现在有一个VLAN资源池,业务需要从资源池中申请一个VLAN,需要你输出从VLAN资源池中移除申请的VLAN后的资源池。
第一行为字符串格式的VLAN资源池,第二行为业务要申请的VLAN,VLAN的取值范围为[1,4094]之间的整数。
输出描述:从输入VLAN资源池中移除申请的VLAN后字符串格式的VLAN资源池,输出要求满足题目描述中的格式,并且按照VLAN从小到大升序输出。
例子:
1-5
2
输出
1,3-5
/**
 * VLAN资源池  --  遍历数组当含-时获取头尾,且判断如果在区间中就拆分区间 ,n不加入,最后组合到数组中进行删除数值,最后通过-后面的数值排序
 *
 */

let arr = ["5", "1-3"];
const n = 10;
const temp = [];
for (let i = 0; i < arr.length; i++) {
  if (arr[i].indexOf("-") > -1) {
    let start = Number(arr[i].split("-")[0]);
    let end = Number(arr[i].split("-")[1]);
    if (n <= end && n >= start) {
      let str1 = n - start > 1 ? start + "-" + n - 1 : String(start);
      let str2 = end - n > 1 ? n + 1 + "-" + end : String(end);
      arr.splice(i, 1);
      temp.push(str1, str2); //拆分出的区间
    }
  }
}
arr = arr.concat(temp); //加入拆分的内容
const index = arr.indexOf(String(n));
if (index > -1) {
  arr.splice(index, 1); //删除对应数值
}
arr.sort((a, b) => {
  const aa = Number(a.split("-")[a.split("-").length - 1]);
  const bb = Number(b.split("-")[b.split("-").length - 1]);
  return aa - bb;
});
console.log(arr.join());

字符串摘要

给定一个字符串的摘要算法,请输出给定字符串的摘要值。
1、去除字符串中非字母的符号。
2、如果出现连续字符(不区分大小写),则输出:该字符(小写)+ 连续出现的次数。
3、如果是非连续的字符(不区分大小写),则输出:该字符(小写)+ 该字母之后字符串中出现的该字符的次数。
4、对按照以上方式表示后的字符串进行排序:字母和紧随的数字作为一组进行排序,数字大的在前,数字相同的,则按字母进行排序,字母小的在前。
示例:
输入
aabbcc
输出
a2b2c2
/**
 * 字符串摘要 -- 滑窗判断重复, 及时对重复的下标i跳加,进行字符串拼接放入数组 最后通过split取出数字排序
 *
 */
let n = "bAaCcAcBb".replaceAll(/[^a-zA-z]/g, "").split("");
let arr = [];
for (let i = 0; i < n.length; i++) {
  let repeat = 0;
  for (let j = i + 1; j < n.length; j++) {
    if (n[i].toLowerCase() === n[j].toLowerCase()) { //比对下j个是否和当前i一样的连续字符并累加
      repeat++;
    } else {
      break;
    }
  }
  if (repeat) {
    i += repeat;
    arr.push(n[i].toLowerCase() + (repeat + 1)); //如有重复推进数组并跳i
  } else {
    let apear = n
      .slice(i + 1)
      .filter((item) => item.toLowerCase() === n[i].toLowerCase()).length;
    arr.push(n[i] + apear); //否则没有 截断前面的数组并统计字符出现次数
  }
}
arr.sort((a, b) => { //排序规则
    if (b.split("")[1] === a.split("")[1]){
        return a.split("")[0].charCodeAt() - b.split("")[0].charCodeAt();
    }
      return b.split("")[1] - a.split("")[1];
});
console.log(arr.join(""));

单词接龙

描述:单词接龙的规则是:可用于接龙的单词首字母必须要前一个单词的尾字母相同;当存在多个首字母相同的单词时,取长度最长的单词,如果长度也相等,则取字典序最小的单词;已经参与接龙的单词不能重复使用。
现给定一组全部由小写字母组成单词数组,并指定其中的一个单词作为起始单词,进行单词接龙,请输出最长的单词串,单词串是单词拼接而成,中间没有空格。
输入描述:输入的第一行为一个非负整数,表示起始单词在数组中的索引
输入的第二行为一个非负整数,表示单词的个数N;
接下来的N行,分别表示单词数组中的单词。
输出描述:输出一个字符串,表示最终拼接的单词串。
/**
 * 单词接龙  -- while循环不断使用filter头尾相比,多个结果取第一个并排序,没有结果中断循环,每次开始删除上一次生效的word
 *
 */

const arr = ["word", "dd", "da", "dc", "dword", "d"];

const start = 4;

let word = arr[start];
const res = [word];

let notfound = false;
while (!notfound) {
  arr.splice(arr.indexOf(word), 1); //删除掉上次匹配成功的

  let next = arr.filter(
    (item) => item.charAt(0) === word.charAt(word.length - 1)
  );

  if (next.length > 1) {
    //多个结果排序后取第一个
    let temp = next.sort().sort((A, B) => {
      if (B.length !== A.length) {
        return B.length - A.length;
      }
    });
    word = temp[0];
    res.push(temp[0]);
  }
  if (next.length === 1) {
    res.push(next[0]);
    word = next[0];
  }
  if (next.length === 0) {
    notfound = true;
  }
}
console.log(res.join(""));

字符串加密

描述:给你一串未加密的字符串str,通过对字符串的每一个字母进行改变来实现加密,加密方式是在每一个字母str[i]偏移特定数组元素a[i]的量,数组a前三位已经赋值:a[0]=1,a[1]=2,a[2]=4。当i>=3时,数组元素a[i]=a[i-1]+a[i-2]+a[i-3],
例如:原文 abcde 加密后 bdgkr,其中偏移量分别是1,2,4,7,13。
/**
 * 字符串加密 -- 定义字母表 对原数组遍历加密 当前位置加上偏移算法求余26获取偏移位置拼接
 *
 */
let num = "2";
let arr = "abcde";

const zimu = "abcdefghijklmnopqrstuvwxyz";
const list = [];

let sb = "";
for (let j = 0; j < arr.length; j++) {
  let pianyi = jiami(j);
  let index = (zimu.indexOf(arr.charAt(j)) + pianyi) % 26; //需要取余,防止pianyi值过大
  sb += zimu.charAt(index);
}
list.push(sb);
console.log(list[0]);
function jiami(n) {
  //根据要求 0=1,1=2,2=4,大于3时 递归入参-1 加  -2 加  -3
  if (n == 0) {
    return 1;
  }
  if (n == 1) {
    return 2;
  }
  if (n == 2) {
    return 4;
  }
  return jiami(n - 1) + jiami(n - 2) + jiami(n - 3);
}

字符串重新排序

题目描述:给定一个字符串s,s包含以空格分隔的若干个单词,请对s进行如下处理后输出:
1、单词内部调整:对每个单词字母重新按字典序排序;
2、单词间顺序调整:
1)统计每个单词出现的次数,并按次数降序排列;
2)次数相同时,按单词长度升序排列;
3)次数和单词长度均相同时,按字典序升序排列。
请输出处理后的字符串,每个单词以一个空格分隔。
输入:My sister is in the house not in the yard
输出: in in eht eht My is not adry ehosu eirsst
let word = "My sister is in the house not in the yard".split(" ");
word = word.map((item) => {
  return item.split("").sort().join("");
});
let copy = [...word];
const res = word
  .sort((a, b) => {
    //出现次数
    let anums = copy.filter((i) => i === a).length; 
    let bnums = copy.filter((i) => i === b).length;

    if (bnums !== anums) {
      //出现次数不等则 次数降序
      return bnums - anums;
    } else if (b.length !== a.length) {
      //出现次数相等且长度不等 长度升序
      return a.length - b.length;
    } else {
      //出现次数相等且长度相等 字典升序
          return a.charCodeAt(0) - b.charCodeAt(0);
      
    }
  })
  .join(" ");
console.log(res)

静态代码扫描服务

题目描述:静态扫描快速快速识别源代码的缺陷,静态扫描的结果以扫描报告作为输出
1、文件扫描的成本和文件大小相关,如果文件大小为N,则扫描成本为N个金币
2、扫描报告的缓存成本和文件大小无关,每缓存一个报告需要M个金币
3、扫描报告缓存后,后继再碰到该文件则不需要扫描成本,直接获取缓存结果
给出源代码文件标识序列和文件大小序列,求解采用合理的缓存策略,最少需要的金币数。
输入:
5
1 2 2 1 2 3 4
1 1 1 1 1 1 1
输出:7
/**
 * 静态代码扫描服务 
 */
const m = 5;
const ids = [2, 2, 2, 2, 2, 5, 2,2,2];
let idsset = [...new Set(ids)]; //对输入的文件标识去重
const size = [3,3,3,3,3,1,3,3,3];
let sum = 0;

idsset = idsset.forEach(id => {
    let idsize = size[ids.indexOf(id)]; //对应的文件大小
    //对每个文件进行缓存和不缓存的费用比较,取便宜的费用进行累加
  sum += Math.min(
    idsize + m, //缓存费用
    idsize * ids.filter((item) => item === id).length //不缓存费用
  );
});
console.log(sum);

最多提取子串数目

题目描述:给定由[a-z] 26个英文小写字母组成的字符串A和B,其中A中可能存在重复字母,B中不会存在重复字母现从字符串A中按规则挑选一些字母,可以组成字符串B。挑选规则如下:同一个位置的字母只能被挑选一次
被挑选字母的相对先后顺序不能改变求最多可以同时从A中挑选多少组能组成B的字符串
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // Write your code here
  let aline = await readline();
  let bline = await readline();
  let alist = aline.split("");
  let blist = bline.split("");
  let count = 0;
  let n = 1;
  while (n) {
    let temp = [];
    let stack = [...blist]; //栈存储
    for (let i = 0; i < alist.length; i++) {
      if (stack.length == 0) {
        break;
      }
      if (alist[i] == stack[0]) {
        stack.shift(); //出栈
        temp.push(i); //存下标
      }
    }
    if (stack.length == 0) { //栈清空表示成功一轮匹配,继续匹配,直到匹配不出来栈无法清空就结束
      count++;
      while (temp.length > 0) {//删除匹配成功的alist元素
        let j = temp.pop();
        alist.splice(j, 1);
      }
    } else {
      n = 0;
    }
  }
  console.log(count);
})();

箱子之形摆放

题目描述:有一批箱子(形式为字符串,设为str),要求将这批箱子按从上到下以之形的顺序摆放在宽度为n的空地,请输出箱子的摆放结果。
例如:箱子为ABCDEFG,空地宽度为3,摆放结果如图:
image.png

则输出结果为:
AFG
BE
CD


/**
 * 箱子之形摆放 
 */

let strings = "ABCDEFG 3".split(" ");
let box = strings[0];
let n = Number(strings[1]);
let res = [];
let col = 0;
let w = 0; //宽度
for (let i = 0; i < box.length; i++) {
  col = Math.floor(i / n); //当前列数
  if (col === 0) {
    res[w] = [box[i]];
  } else {
    res[w].push(box[i]);
  }
  if (w < n - 1 && col % 2 === 0) {//当小于宽度时且为偶数列宽度递增
    w++;
  }
  if (w > 0 && col % 2 !== 0) {//为奇数列宽度进行递减
    w--;
  }
}

res.forEach((item) => console.log(item.join("")));

投篮大赛

image.png
image.png

/**
 * 投篮大赛
 */
const arr = ['5', 'D' ,'4', 'C', 'D','9','+' ,'+'];

let res = 0
let i=0;
while (arr[i] !== undefined) {
  arr[i] = isNaN(arr[i]) ? arr[i] : Number(arr[i]);

  if (arr[i + 1] && arr[i + 1] === "C") { //当下一个为C清除C和当前项
  arr.splice(i, 2);
  }
  if (arr[i] && arr[i] === "D") { //为D 变化为上一个2倍
    arr[i] = arr[i - 1] * 2;
  }
  if (arr[i + 1] && arr[i +1] === "+") { //下一个为+则对当前和上一个相加
    arr[i + 1] = arr[i] + Number(arr[i - 1]);
  }
  res += Number(arr[i]);
  i++;
}
console.log(isNaN(res)? -1: res);

寻找链表的中间结点

image.png

/**
 * 寻找链表的中间结点 
 */
const node = ['76892 7 12309','12309 5 -1', '10000 1 76892'];
const head = '10000';

const nodemap = {};
node.forEach(item =>{
    const [addr, val, next] = item.split(' ');
    nodemap[addr] = { //map地址映射存储所有链表数据
        val,
        next
    }
});

let len = 0;
let currnodeNext = head;
while (currnodeNext !== "-1") { //获取到len的真实链表长度 (链表运动)
  currnodeNext = nodemap[currnodeNext].next;
  len++;
}
let center = Math.floor(len /2); //中位数

let currt = nodemap[head];
while(center--){ //链表运动到中位数停止 ,从而得到结果
currt = nodemap[currt.next];
}
console.log(currt.val);

获取最大软件版本号

image.png
image.png

/**
 * 获取最大软件版本号
 */
const arr = ["1.05.1", "1.5.01"];
let version1 = arr[0].split("-")[0].replaceAll(".", ""),
  version2 = arr[1].split("-")[0].replaceAll(".", "");
if (version1.length > version2.length) {
  version2 = version2 + "0".repeat(version1.length - version2.length);
} else {
  version1 = version1 + "0".repeat(version2.length - version1.length);
}
if (Number(version1) > Number(version2)) {
  return console.log(arr[0]);
}

if (Number(version1) < Number(version2)) {
  return console.log(arr[1]);
}
if (
  arr[0].split("-")[1].charAt(0).charCodeAt() <
  arr[1].split("-")[1].charAt(0).charCodeAt()
) {
  console.log(arr[1]);
} else {
  console.log(arr[0]);
}

洛阳醉长安行
57 声望3 粉丝

charging...