牛客网华为机试题训练汇总(JavaScript)

牛客网华为机试题训练(JavaScript Node环境)



前言

  1. 题目摘录牛客网华为机试题,答案为作者亲自操刀编码。

  2. 直接拷贝代码即可运行,记得如下运行环境:
    在这里插入图片描述


一、题目


1. HJ11 数字颠倒

描述:
输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001

输入描述:
输入一个int整数

输出描述:
将这个整数以字符串的形式逆序输出

示例1:

输入:1516000
输出:0006151

答案: (思路:转成字符串数组,反转,再转成字符串)

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})

rl.on('line', (str) => {
    deal(str)
})

function deal(str) {
    let result = [...str].reverse().join('');
    console.log(result)
}

rl.on('close', () => {
    rl.close();
})


2. HJ22 汽水瓶

描述
有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?

输入描述:
输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=100),表示小张手上的空汽水瓶数。n=0表示输入结束,你的程序不应当处理这一行。

输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。

示例1

输入:
3
10
81
0
输出:
1
5
40

答案:(思路:空瓶两个则换1瓶; 空瓶1个则换0瓶;多于两个对3取整再加余数为手头的空瓶数,则递归调用当前函数)

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})

rl.on('line', (str) => {
    let num = Number(str);
    if (num !== 0) {
        let result = getNum(Number(str))
        console.log(result)
    }

})

rl.on('close', () => {
    rl.close();
})

function getNum(num) {
    if (num === 2) {  //两个空瓶
        return 1;
    }
    if (num === 1) {  //一个空瓶
        return 0;
    }
    if (num > 2) {
        let q = Math.floor(num / 3);
        let r = num % 3;
        return q + getNum(q + r);
    }
}


3. HJ53 杨辉三角的变形

描述
在这里插入图片描述

以上三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数,左上角数到右上角的数,3个数之和(如果不存在某个数,认为该数就是0)。

求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3。

输入n(n <= 1000000000)
本题有多组输入数据,输入到文件末尾,请使用while(cin>>)等方式读入
输入描述:
输入一个int整数

输出描述:
输出返回的int值

示例1

输入:
4
2
输出:
3
-1

答案一:
(思路:从第一行依次构造整个变形杨辉三角二维数组,没有数值的地方填充0。 缺点:浪费内存,效率低

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})


// n  行数
rl.on('line', (str) => {
    let n = Number(str)
    let resultArray = createTriangle(n);
    let pos = getEven(resultArray, n)
    console.log(pos)

})

rl.on('close', () => {
    rl.close();
})


//构造变形杨辉三角
function createTriangle(n) {
    let row = n;
    let col = 2 * n - 1;
    //初始化二维数组
    let array = initArray(row, col);


    //初始化第一行元素
    let pos = Math.floor(col / 2);
    let firstLine = Array(col).fill(0);
    firstLine[pos] = 1;
    array[0] = firstLine;


    // 根据第一行依次初始化后面各行 注意边界值:j=0 和  j=col-1
    for (let i = 1; i < row; i++) {
        for (let j = 0; j < col; j++) {
            if (j === 0) {
                array[i][j] = array[i - 1][j] + array[i - 1][j + 1]
            } else if (j === col - 1) {
                array[i][j] = array[i - 1][j - 1] + array[i - 1][j]
            } else {
                array[i][j] = array[i - 1][j - 1] + array[i - 1][j] + array[i - 1][j + 1]
            }
        }
    }

    return array

}

//初始化二维数组
function initArray(row, col) {
    let array = new Array(row);
    for (let i = 0; i < row; i++) {
        array[i] = new Array(col);
        for (let j = 0; j < col; j++) {
            array[i][j] = 0;
        }
    }
    return array;
}

//找出二维数组,第n行,第一个偶数
function getEven(array, n) {

    let arr = array[n - 1];
    let index = arr.findIndex((_el) => {
        return _el % 2 === 0;
    })
    return index === -1 ? '-1' : index + 1;

}

答案二:
(思路:已知,第一行数据,递归调用获取第n行数据。条件:arr[n][m] = arr[n-1][m]+arr[n-1][m-1]+arr[n-1][m-2]。 缺点:函数调用开支大,效率低

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})


// n  行数
rl.on('line', (str) => {
    let n = Number(str)
    let resultArray = getArr(n);

    let pos = getEven(resultArray)
    console.log(pos)

})

rl.on('close', () => {
    rl.close();
})


/**
 * 获取第n行数组
 * @param row 行号
 */
function getArr(row) {
    if (row === 1) {  //第一行
        return [1]
    }

    let col = 2 * row - 1;
    let arr = new Array(col).fill(0); //当前行数组长度,默认填充0;
    let preArr = getArr(row - 1);
    for (let j = 0; j < col; j++) {
        arr[j] = (preArr[j - 2] || 0) + (preArr[j - 1] || 0) + (preArr[j] || 0);
    }
    return arr;

}


//找出数组第一个偶数
function getEven(arr) {
    let index = arr.findIndex((_el) => {
        return _el % 2 === 0;
    })
    return index === -1 ? '-1' : index + 1;

}


4. HJ2 计算某字母出现次数

描述
写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字母,然后输出输入字符串中该字母的出现次数。不区分大小写,字符串长度小于500。

输入描述:
第一行输入一个由字母和数字以及空格组成的字符串,第二行输入一个字母。

输出描述:
输出输入字符串中含有该字符的个数。

示例1

输入:
ABCabc
A
输出:
2

答案
(思路:正则匹配即可,忽略大小写)

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
})

let inputStrArr = [];
let index = 0;

rl.on('line', (str) => {
    inputStrArr[index] = str;
    index++;
    if (inputStrArr.length === 2) {
        let reg = new RegExp(inputStrArr[1], "gi");
        let result = inputStrArr[0].match(reg);
        console.log(result)
        if (result) {
            console.log(result.length)
        } else {
            console.log(0)
        }

    }
})
rl.on('close', () => {
    rl.close;
})


5. HJ8 合并表记录

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

输入描述:
先输入键值对的个数
然后输入成对的index和value值,以空格隔开

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

示例1

输入:
4
0 1
0 2
1 2
3 4
输出:
0 3
1 2
3 4

答案
(思路:每一行都存入数组,如:[“4”, “0 1”, “0 2”, “1 2”, “3 4”],根据数据个数遍历,使用空格符分割,存入到对象,对象key已经存在,则value相加,否则新增对象属性;最后遍历对象输出即可)

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
})

rl.on('close', () => {
    rl.close;
})

let inputArr = [];
let index = 0;

rl.on('line', (str) => {
    inputArr[index] = str;
    index++;
    let num = Number(inputArr[0]);
    if (num + 1 === inputArr.length) {
        let resultObj = {};
        for (let i = 1; i <= num; i++) {
            let tempArr = inputArr[i].split(' ');
            let key = tempArr[0];
            if (Object.prototype.hasOwnProperty.call(resultObj, key)) {
                resultObj[key] += Number(tempArr[1]);
            } else {
                resultObj[key] = Number(tempArr[1]);
            }
        }

        printObj(resultObj)

    }
})


function  printObj(object){
    for (const obj in object) {
        console.log(obj+" "+ object[obj])
    }
}



6. HJ17 坐标移动

描述
开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。

输入:

合法坐标为A(或者D或者W或者S) + 数字(两位以内)

坐标之间以;分隔。

非法坐标点需要进行丢弃。如AA10; A1A; % ; YAD; 等。

下面是一个简单的例子 如:

A10;S20;W10;D30;X;A1A;B10A11;;A10;

处理过程:

起点(0,0)

  • A10 = (-10,0)

  • S20 = (-10,-20)

  • W10 = (-10,-10)

  • D30 = (20,-10)

  • x = 无效

  • A1A = 无效

  • B10A11 = 无效

  • 一个空 不影响

  • A10 = (10,-10)

结果 (10, -10)

注意请处理多组输入输出

输入描述:
一行字符串

输出描述:
最终坐标,以逗号分隔

示例1

输入:
A10;S20;W10;D30;X;A1A;B10A11;;A10;
输出:
10,-10

答案
(思路:通过正则匹配找到合法的字符串,放入到数组中,然后遍历数据移动坐标即可)

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
})

rl.on('close', () => {
    rl.close;
})


rl.on('line', (str) => {

    let dataArr = getIegalStr(str)
    let pos = move(dataArr);
    console.log(pos.join(','))

})

/**
 * 获取符合要求的字符串数据
 */
function getIegalStr(str) {
    let arr = str.split(";")
    let reg = /^[ADWS]\d{1,2}$/
    let result = [];
    for (let i = 0; i < arr.length; i++) {
        if (reg.test(arr[i])) {
            reg.lastIndex = 0;
            result.push(arr[i]);
        }
    }
    return result;
}

/**
 *  坐标移动
 * @param dataArr
 * @returns {number[]}
 */
function move(dataArr) {
    let origin = [0, 0];
    const len = dataArr.length;
    for (let i = 0; i < len; i++) {
        let str = dataArr[i];
        let num = Number(str.slice(1))
        switch (str.slice(0, 1)) {
            case "A":
                origin[0] -= num
                break;
            case "D":
                origin[0] += num
                break;
            case "W":
                origin[1] += num
                break;
            case "S":
                origin[1] -= num
                break;
        }
    }
    return origin;

}


7. HJ77 火车进站

描述
给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1-9编号,火车站只有一个方向进出,同时停靠在火车站的列车中,只有后进站的出站了,先进站的才能出站。
要求输出所有火车出站的方案,以字典序排序输出。
输入描述:
有多组测试用例,每一组第一行输入一个正整数N(0

输出描述:
输出以字典序从小到大排序的火车出站序列号,每个编号以空格隔开,每个输出序列换行,具体见sample。

示例1

输入:
         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 readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
})

rl.on('close', () => {
    rl.close;
})

let inputArr = [];

rl.on('line', (str) => {
    inputArr.push(str)
    if (inputArr.length === 2) {
        let arr = inputArr[1].split(' ')
        let allSeq = getLegalArray(arr);
        printArr(allSeq.sort()); //输出字典排序
    }
})

/**
 * 获取合法的出栈序列
 * 步骤   1、获取原始数组的全排列
 *        2、从全排列中过滤出合法的序列 即为出栈序列
 *
 * @param arr  原始数组
 * @returns {[]}
 */
function getLegalArray(arr) {

    const len = arr.length;
    let result = [];
    const originArray = JSON.parse(JSON.stringify(arr));

    function func(index = 0) {
        for (let i = index; i < len; i++) {
            // 交换数组元素
            swap(arr, i, index);
            if (index < len - 1) {
                //index+1 后的元素全排列
                func(index + 1)
            } else {
                //console.log(arr);
                if (isLegal(arr, originArray)) {  //是否合法的出栈序列
                    result.push(JSON.parse(JSON.stringify(arr)))
                }
            }
            //恢复数组元素原来顺序
            swap(arr, i, index);
        }
    }

    func(0);
    return result;
}


/**
 * 交换数组i、j位置元素
 * @param arr
 * @param i
 * @param j
 */

function swap(arr, i, j) {
    if (i === j) {
        return;
    }
    let temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

/**
 *  从全排列中过滤合法的出栈序列
 *  条件: 1、待入栈序列依次入栈
 *        2、栈顶元素和出栈序列队头元素比较,相等则出栈;否则,继续入栈
 *        3、入栈序列全部入栈,判断栈中元素是否为空,为空:说明出栈序列事合法的序列,否则,不合法
 *
 * @param popQueue  待判断的出栈序列(二维数组、全排列)
 * @param pushQueue       入栈序列
 */

function isLegal(popQueue, pushQueue) {
    //栈内元素
    const stack = [];

    const pop = JSON.parse(JSON.stringify(popQueue));
    const push = JSON.parse(JSON.stringify(pushQueue));

    for (let i = 0; i < push.length; i++) {
        stack.push(push[i]);
        //栈顶元素是否和出栈序列队头元素相等
        while (stack.length > 0 && pop[0] === stack[stack.length - 1]) {
            stack.pop(); //栈顶元素出栈
            pop.splice(0, 1); //移除队头元素
        }
    }
    return stack.length === 0;
}

function printArr(arrays) {
    for (let i = 0; i < arrays.length; i++) {
        console.log(arrays[i].join(' '))
    }
}



8. HJ105 记负均正II

描述
输入 n 个整型数,统计其中的负数个数并求所有非负数的平均值,结果保留一位小数,如果没有非负数,则平均值为0
本题有多组输入数据,输入到文件末尾。
在这里插入图片描述

输入描述:
输入任意个整数,每行输入一个。

输出描述:
输出负数个数以及所有非负数的平均值

示例 1

输入:
         -13
         -4
         -7
输出:
         3
         0.0

示例 2

输入:
         -12
         1
         2
输出:
         1
         1.5

答案 :

const readline = require('readline');

let rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,

})

let numArr = []
let count = 0;
rl.on('line', function f(line) {
    let num = Number(line);
    if (num >= 0) {
        numArr.push(num);
    } else {
        count++
    }
})

rl.on('close', function () {
    getAvg();
})

function getAvg() {
    let total = 0;
    let avg = 0;
    numArr.forEach((el) => {
        total += el;
    })
    if (numArr.length > 0) {
        avg = (total / numArr.length);
    }
    avg = avg.toFixed(1)
    console.log(count)
    console.log(avg);

}

二、其他题目

1. 分糖

小明抓一把糖果并平分出去一半给同学,不够分的可以加一颗或减一颗,加一减一平分都算分一次求最少几次分完(最少几次分到只剩一个)。(输入为第一把糖果的数量)

const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})


let num;

rl.on('line', function (line) {
    num = Number(line);
    count = 0;
    getCount(num);
    console.log(Math.min(count))

})

rl.on('close', function (line) {

})

/**
 * 递归计数
 * @param num
 */
let count = 0;

function getCount(num) {
    if (num === 1) {
        return;
    }
    count++;
    if (num % 2 === 0) {
        num /= 2;
        getCount(num)
    } else {

        if (isAdd(num)) {
            num += 1;
        } else {
            num -= 1;
        }
        getCount(num)
    }
}

/**
 *
 * @param num
 *
 * 1、num必为奇数
 * 2、num加 1 或 减 1: 求得当前num临近的两个 2的n次幂数; num向就近的次幂数靠拢,即决定了加还是减操作。
 * @returns {boolean}
 */
function isAdd(num) {

    //求得num底数
    let baseNum = Math.log(num) / Math.log(2)
    let distanceCeil = Math.abs(Math.pow(2, Math.ceil(baseNum)) - num);
    let distanceFloor = Math.abs(Math.pow(2, Math.floor(baseNum)) - num);
    console.log(num,distanceCeil,distanceFloor,Math.ceil(baseNum), Math.floor(baseNum))

    return distanceCeil < distanceFloor
}

总结

每天记录一点,从小小菜鸟变小菜鸟!!!

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hui-1018

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值