华为机试刷题笔记本(中等) - JavaScript V8 未完

332 阅读7分钟

题目地址:www.nowcoder.com/ta/huawei

从易到难,慢慢刷题!

未必能100%通过用例,写的难看,复杂度还高,哎,丢死人了。

HJ6 质数因子

描述

功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )

数据范围: 

输入描述:

输入一个整数

输出描述:

按照从小到大的顺序输出它的所有质数的因子,以空格隔开。最后一个数后面也要有空格。

示例1

输入:

180

输出:

2 2 3 3 5

解题

本质是寻找一个数的所有质数因子

let num;
while(num = parseInt(readline())){
    console.log(prime_factors(num));
}
function prime_factors(num){
    let i = 2;
    let arr = [];
    while(i <= Math.sqrt(num) && i*i <= num){
        if(num%i === 0){
            arr.push(i);
            num = num / i;
            i = 2
        }
        else{
            i++;
        }
    }
    if (num !== 1) {
        arr.push(num)
    }
    let str = arr.join(' ');
    return str;
}

HJ8 合并表记录

## 描述

数据表记录包含表索引和数值(int范围的正整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。

提示:

0 <= index <= 11111111

1 <= value <= 100000

输入描述:

先输入键值对的个数n(1 <= n <= 500)
然后输入成对的index和value值,以空格隔开

输出描述:

输出合并后的键值对(多行)

示例1

输入:

4
0 1
0 2
1 2
3 4

输出:

0 3
1 2
3 4

解题

本想试试看map,结果忘了还要对key进行排序,sort在这方面不好使,还是老老实实用obj。

let arr = [];
let line;
while(line = readline()){
    arr.push(line);
}
let len = arr.splice(0,1);
let map = {};
for(let i=0; i<arr.length;i++){
    let tmp = arr[i].split(' ');
    let key = tmp[0];
    let value = parseInt(tmp[1]);
    if(map[key]){
        let new_value = map[key] + value;
        map[key] = new_value;
    }
    else{
        map[key] = value;
    }
}
Object.keys(map).forEach((el) => {
   console.log(`${el} ${map[el]}`)
})

HJ9 提取不重复的整数

描述

输入一个 int 型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。 保证输入的整数最后一位不是 0 。

数据范围: \

输入描述:

输入一个int型整数

输出描述:

按照从右向左的阅读顺序,返回一个不含重复数字的新的整数

示例1

输入:

9876673

输出:

37689

解题

本质:数组去重

let line;
while(line = readline()){
    let arr = line.split('').reverse();
    let tmp = Array.from(new Set(arr)).join('');
    console.log(tmp)
}

HJ10 字符个数统计

描述

编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次

例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。

数据范围: \

输入描述:

输入一行没有空格的字符串。

输出描述:

输出 输入字符串 中范围在(0~127,包括0和127)字符的种数。

示例1

输入:

abc

输出:

3

示例2

输入:

aaa

输出:

1

解题

将问题转化为数组去重 => Set 去重

let line;
while(line = readline()){
    line = line.split('');
    let set = new Set(line);
    console.log(set.size)
}

HJ14 字符串排序

描述

给定 n 个字符串,请对 n 个字符串按照字典序排列。

数据范围:  ,字符串长度满足 

输入描述:

输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。

输出描述:

数据输出n行,输出结果为按照字典序排列的字符串。

示例1

输入:

9
cap
to
cat
card
two
too
up
boat
boot

输出:

boat
boot
cap
card
cat
to
too
two
up

解题

let line;
let arr = [];
while(line = readline()){
    arr.push(line);
}
let len = arr.splice(0,1);
arr.sort();
arr.forEach((each)=>console.log(each));

HJ21 简单密码

描述

密码是我们生活中非常重要的东东,我们的那么一点不能说的秘密就全靠它了。哇哈哈. 接下来渊子要在密码之上再加一套密码,虽然简单但也安全。

假设渊子原来一个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 哦。

数据范围: 输入的字符串长度满足 

本题有多组样例输入

输入描述:

输入包括多个测试数据。输入是一个明文,密码长度不超过100个字符,输入直到文件结尾\

输出描述:

输出渊子真正的密文

示例1

输入:

YUANzhi1987

输出:

zvbo9441987

解题

code to char String.fromCharCode()

char to code str.charCodeAt(index)

// 小写字母遵循九宫格转化为数字:arr, key为数字,值为被转化对象
// 大写字母通过 char-code 转化
// 数字不变
let line;
while(line = readline()){
    console.log(code_replace(line));
}
function code_replace(line){
    let arr = line.split('');
    let upper_reg = /[A-Z]/;
    let lower_reg = /[a-z]/;
    const char_to_num = ['0','1','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz'];
    let new_pwd = [];
    arr.forEach((char) =>{
        // 大写字母
        if(upper_reg.test(char)){
            if(char === 'Z'){
                new_pwd.push('a')
            }
            else{
                let tmp = String.fromCharCode(char.charCodeAt(0) + 1).toLowerCase();
                new_pwd.push(tmp)
            }
        }
        // 小写字母
        else if(lower_reg.test(char)){
            for(let i=0; i<char_to_num.length; i++){
                if(char_to_num[i].includes(char)){
                    new_pwd.push(i);
                }
            }
        }
        // 数字
        else{
            new_pwd.push(char);
        }
    })
    new_pwd = new_pwd.join('');
    return new_pwd;
}

HJ26 字符串排序

## 描述

编写一个程序,将输入字符串中的字符按如下规则排序。

规则 1 :英文字母从 A 到 Z 排列,不区分大小写。

如,输入: Type 输出: epTy

规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb

规则 3 :非英文字母的其它字符保持原来的位置。

如,输入: By?e 输出: Be?y

注意有多组测试数据,即输入有多行,每一行单独处理(换行符隔开的表示不同行)

数据范围:输入的字符串长度满足  

输入描述:

输入字符串

输出描述:

输出字符串

示例1

输入:

A Famous Saying: Much Ado About Nothing (2012/8).

输出:

A aaAAbc dFgghh: iimM nNn oooos Sttuuuy (2012/8).

解题

let line;
while(line = readline()){
    line = line.split('');
    let seq = [];
    for(let i=0; i<26; i++){
        for(let j=0; j<line.length; j++){
            // 从 a-z 按顺序将字母从取出检查
            let char = line[j];
            if(line[j].charCodeAt(0) === 65 + i || line[j].charCodeAt(0) === 97 + i){
                seq.push(line[j]);
                line[j] = '';
            }
        }
    }
    for(let i=0; i<line.length; i++){
        if(line[i] === ''){
            line[i] = seq.splice(0,1);
        }
    }
    line = line.join('');
    console.log(line)
    
}

HJ34 图片整理

描述

Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。请大家给Lily帮忙,通过C语言解决。

本题含有多组样例输入。

数据范围:每组输入的字符串长度满足 

输入描述:

Lily使用的图片包括"A"到"Z"、"a"到"z"、"0"到"9"。输入字母或数字个数不超过1024。

输出描述:

Lily的所有图片按照从小到大的顺序输出 示例1

输入:

Ihave1nose2hands10fingers

输出:

0112Iaadeeefghhinnnorsssv

解题

非常幸运,js array sort() 就是按ASCII排序的

let line;
while(line = readline()){
    line = line.split('').sort().join('');
    console.log(line);
}

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

解题

有点像凯撒密码的变形

array重组,去重,a 的 ASCII 编码为97,减去97即得到array中对应的 index

let key;
while(key = readline()){
    let raw = readline();
    console.log(encryption(key,raw));
    
}
function encryption(key, raw){
    let alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
    let seq = key.split('').concat(alphabet);
    let encrypted = [];
    seq = Array.from(new Set(seq));
    for(let i=0; i<raw.length; i++){
        let index = raw.charCodeAt(i) - 97;
        let char = seq[index];
        encrypted.push(char);
    }
    encrypted = encrypted.join('');
    return encrypted;
}

HJ38 求小球落地5次后所经历的路程和第5次反弹的高度

描述

假设一个球从任意高度自由落下,每次落地后反跳回原高度的一半; 再落下, 求它在第5次落地时,共经历多少米?第5次反弹多高?

最后的误差判断是小数点6位

数据范围:输入的小球初始高度满足  ,且保证是一个整数

输入描述:

输入起始高度,int型

输出描述:

分别输出第5次落地时,共经过多少米第5次反弹多高

示例1

输入:

1

输出:

2.875
0.03125

解题

保留有效数位 toFixed(num)

let height;
while(height = parseInt(readline())){
    let length = height;
    for(let i=0; i<5; i++){
        height = height / 2;
        i < 4 ? length += height*2 : length;

    }
    console.log(length);
    console.log(height.toFixed(5));
}

HJ40 统计字符

描述

输入一行字符,分别统计出包含英文字母、空格、数字和其它字符的个数。

本题包含多组输入。

数据范围:输入的字符串长度满足 

输入描述:

输入一行字符串,可以有空格

输出描述:

统计其中英文字符,空格字符,数字字符,其他字符的个数

示例1

输入:

1qazxsw23 edcvfr45tgbn hy67uj m,ki89ol.\/;p0-=\][

输出:

26
3
10

解题

考察正则用法

let line;
while(line = readline()){
    let regs = [/[A-Za-z]/g, /\s/g, /[\d]/g, /[^a-zA-Z\d\s]/g]
    let results = []
    regs.forEach((reg)=>{
        let matches = line.match(reg);
        let len = get_length(matches);
        results.push(len);
    });
    results.forEach((len)=>{
        console.log(len);
    })
}
function get_length(content){
    let len = content !== null? content.length : 0;
    return len;
}

HJ45 名字的漂亮度

描述

给出一个名字,该名字有26个字符组成,定义这个字符串的“漂亮度”是其所有字母“漂亮度”的总和。
每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个不同字母拥有相同的“漂亮度”。字母忽略大小写。

给出多个名字,计算每个名字最大可能的“漂亮度”。

本题含有多组数据。

数据范围:输入的名字长度满足 

输入描述:

整数N,后续N个名字 输出描述:

每个名称可能的最大漂亮程度\

示例1

输入:

2
zhangsan
lisi

输出:

192
101

解题

又是一道题面文字游戏。本质是求字符串中重复的字符,然后按重复次数自大到小乘以26到1.

let line;
let num = readline();
while(line = readline()){
let freq = {};
line = line.split('');
let len = line.length;
    for(let i=0; i<len; i++){
        let tmp = line.splice(0,1);
        if(tmp in freq){
            freq[tmp] += 1
        }
        else{
            freq[tmp] = 1;
        }
    }
    let arr = [];
    for(let v in freq){
      arr.push(freq[v])
    }
    arr = arr.sort((a,b)=>{
      return b-a;
    })
    let result = 0;
    for(let j=0; j<arr.length; j++){
        result += arr[j]*(26-j);
    }
    console.log(result);
 
  
}

HJ46 截取字符串

描述

输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出

本题输入含有多组数据

数据范围:字符串长度满足  , 

输入描述:

1.输入待截取的字符串

2.输入一个正整数k,代表截取的长度

输出描述:

截取后的字符串

示例1

输入:

abABCcDEF
6

输出:

abABCc

示例2

输入:

ffIKEHauv
1
bdxPKBhih
6

输出:

f
bdxPKB

解题

甚至没明白这题意义何在啊,不禁用API的话,一个substring就完事

let line;
while(line = readline()){
    let num = parseInt(readline());
    console.log(line.substring(0,num));
    
}

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

数据范围:链表长度满足  ,节点中的值满足 

测试用例保证输入合法

输入描述:

输入一行,有以下4个部分:

1 输入链表结点个数
2 输入头结点的值
3 按照格式插入各个结点
4 输入要删除的结点的值\

输出描述:

输出一行

输出删除结点后的序列,每个数后都要加空格

示例1

输入:

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

说明:

如题 

解题

这题没写完,本质就是手写linked list,如果只求一个输出,我真的就想直接用array写了。毕竟js的array没有长度限制,本身非常灵活。

let Node = function(element){
    this.element = element;
    this.next = null;
}
class LinkedList{
    constructor(){
        this.length = 0;
        this.head = null;
    }

    getElementAt(position){
        // 检查 position 是否合法
        if(position < 0 || position >= this.length){
            return null;
        }
        else{
            // 从头部开始遍历每个node
            let curr = this.head;
            for(let i=0; i<position; i++){
                curr = curr.next;
            }
        }
    }
    append(element){
        let node = new Node(element);
        if(this.head === null){
            this.head = node;
        }
        else{
            let curr = this.getElementAt(this.length-1);
            curr.next = node;
        }
    }
    insert(position, element){
        if(position < 0 || position >= this.length){
            return false;
        }
        else{
            let node = new Node(element);

            // 替换首个元素
            if(position === 0){
                node.next = this.head;
                this.head = node;
            }
            else{
                let previous = this.getElementAt(position -1);
                node.next = previous.next;
                previous.next = node;
            }
        }
        this.length += 1;
        return true;
    }
    removeAt(position){
        if(position < 0 || position >= this.length){
            return false;
        }
        else{
            let curr = this.head;
            if(position ===0){
                this.head = curr.next;
            }
            else{
                let previous = this.getElementAt(position-1);
                let curr = previous.next;
                previous.next = curr.next;
            }
        }
        this.length -= 1;
        return true;
    }
}
let line = "5 2 3 2 4 3 5 2 1 4 3";
line = line.split(' ');
let rm = parseInt(line.splice(line.length-1,1));
let len = parseInt(line.splice(0,1));
let start = parseInt(line.splice(0,1));

let list = new LinkedList();
list.length = len;
list.head = new Node(start);