华为研发工程师编程题——明明的随机数

题目

[编程题]明明的随机数------来自牛客的华为研发工程师编程题,难度:🌟🌟🌟🌟

对于明明生成的 n 个 1 到 500 之间的随机整数,你需要帮助他完成以下任务:

∙删去重复的数字,即相同的数字只保留一个,把其余相同的数去掉;

∙然后再把这些数从小到大排序,按照排好的顺序输出。

你只需要输出最终的排序结果。

输入描述:

第一行输入一个整数 n (1≦n≦1000),代表明明生成的数字个数。

此后 n 行,第 i 行输入一个整数 ai (1≦ai ≦500),代表明明生成的随机整数。

输出描述:

输出若干行,每行输出一个整数,代表输入数据排序后的结果。第一行输出最小的数字。

示例1

输入

3

2

2

1

输出

1

2

解题
数组+插入排序

由于一开始没想起插入排序最好用链表来做,所以先写了数组版,思路如下:

  1. 读取输入的第一行,获得随机整数的总数
  2. 新建一个空数组nums,用来收集各输入数,存入nums的元素要遵循递增(即从小到大、不允许重复)的规则
  3. ACM输入的第一个整数存入nums第一位,后面的输入数逐个插入nums或被去重,直到处理完所有输入数。每次处理输入数都遵循以下处理流程:
    1. 处理流程第一步,读取下一个输入数作为新的待插入元素newNum,选取nums最后一个元素作为新的被比较元素compareNum,比较newNum与compareNum的大小
    2. newNum = compareNum,说明newNum是重复的数字,不必保留。回到处理流程第一步
    3. newNum > compareNum,则newNum大于compareNum及其左边的所有数,应把newNum插入nums中当前compareNum的后一位(nums.splice(compareNum的index + 1, 0, newNum))。回到处理流程第一步
    4. newNum < compareNum,且compareNum是nums中的第一位,说明newNum比nums中所有元素都要小,应把newNum插入nums的第一位(nums.unshift(newNum))。回到处理流程第一步
    5. newNum < compareNum,且compareNum不是nums中的第一位,说明newNum如果要插入的话,它的索引会比compareNum的索引更小,但还不知道具体是多少。应选取当前compareNum的前一位作为新的compareNum。回到处理流程第二步
  4. 处理完所有输入数后,nums就是一个包含所有输入数的数值且按递增顺序排列的数组了,现在遍历nums并打印出来。
typescript 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});
const inputLines = [];
rl.on("line", function (line: string) {
    inputLines.push(line.trim());
});
rl.on("close", function () {
    const numsLength = parseInt(inputLines[0]);
    // 数组nums是递增序列
    const nums = [];
    nums.push(parseInt(inputLines[1]));
    // 遍历输入数
    // 若新输入数按顺序插入了nums,或与已有元素重合了,则处理下一个输入数
    for (let newNumIdx = 2; newNumIdx <= numsLength; newNumIdx++) {
        const newNum = parseInt(inputLines[newNumIdx]);
        // 遍历nums
        let compareNumIdx = nums.length - 1;
        while (compareNumIdx >= 0) {
            const compareNum = nums[compareNumIdx];
            if (newNum === compareNum) {
            	// 退出nums遍历,去读取下一个输入数
                break;
            } else if (newNum > compareNum) {
            	// 插入新元素
                nums.splice(compareNumIdx + 1, 0, newNum);
                // 退出nums遍历,去读取下一个输入数
                break;
            } else {
                if (compareNumIdx === 0) {
                	// 在队首插入新元素
                    nums.unshift(newNum);
                    // 退出nums遍历,去读取下一个输入数
                	break;
                } else {
                	// 选取原被比较数的前一位作为新被比较数
                	compareNumIdx--;
                }
            }
        }
    }
    nums.forEach((num) => {
        console.log(num);
    });
});

遇到的问题:

  1. ACM输入问题一定要记得把输入字符串中的数字部份转为整数类型,否则把数字字符串当数字使用会出问题。比如1000>2是对的,但'1000'>'2'是错的,如果按从小到大排,程序会把'1000'排在'2'的前面。
  2. 流程比较复杂,主要是要熟悉插入排序的实现。
  3. 各循环的灵活度排名:while > for > forEach/map。
    如果想从数组的非开头元素开始遍历,或在非结尾元素结束遍历,或希望每次跳过一个元素,则for比forEach更方便控制。若循环中不同条件下索引可能增加n也可能减少n(最好别这样),则while比for更方便控制。
    视情况选择用哪种,一般用for循环。
链表+插入排序
typescript 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});
const inputLines = [];
class LineNode {
	val?: number; // default:public
   	next: LineNode | null = null;
   	last: LineNode | null = null;
	constructor(val?: number) {
		this.val = val;
		this.next = null;
		this.last = null;
	}
}
rl.on("line", function (line: string) {
    inputLines.push(line.trim());
});
rl.on("close", function () {
    const numsLength = parseInt(inputLines[0]);
    // 递增序列
    const lineHeadNode = new LineNode();

    // 遍历输入数
    // 若新输入数按顺序插入了nums,或与已有元素重合了,则处理下一个输入数
    for (let newNumIdx = 2; newNumIdx <= numsLength; newNumIdx++) {
        const newNum = parseInt(inputLines[newNumIdx]);
        // 遍历nums
        let compareNumIdx = nums.length - 1;
        while (lineHeadNode.last.) {
            const compareNum = nums[compareNumIdx];
            if (newNum === compareNum) {
            	// 退出nums遍历,去读取下一个输入数
                break;
            } else if (newNum > compareNum) {
            	// 插入新元素
                nums.splice(compareNumIdx + 1, 0, newNum);
                // 退出nums遍历,去读取下一个输入数
                break;
            } else {
                if (compareNumIdx === 0) {
                	// 在队首插入新元素
                    nums.unshift(newNum);
                    // 退出nums遍历,去读取下一个输入数
                	break;
                } else {
                	// 选取原被比较数的前一位作为新被比较数
                	compareNumIdx--;
                }
            }
        }
    }
    nums.forEach((num) => {
        console.log(num);
    });
});
相关推荐
拉不动的猪1 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪2 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
uhakadotcom3 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom3 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom3 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom3 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
咖啡教室4 小时前
前端开发日常工作每日记录笔记(2019至2024合集)
前端·javascript
咖啡教室5 小时前
前端开发中JavaScript、HTML、CSS常见避坑问题
前端·javascript·css
算AI7 小时前
人工智能+牙科:临床应用中的几个问题
人工智能·算法
市民中心的蟋蟀7 小时前
第五章 使用Context和订阅来共享组件状态
前端·javascript·react.js