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

题目

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

对于明明生成的 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);
    });
});
相关推荐
民乐团扒谱机17 小时前
【微实验】组合优化matlab实战(马科维茨投资模型):在收益与风险之间,寻找最优的人生配比
大数据·人工智能·算法·机器学习·数学建模·matlab·组合优化
Nil20818 小时前
leetcode 160相交链表
算法·leetcode·链表
迷途之人不知返19 小时前
算法系列2:滑动窗口
算法
Herbert_hwt19 小时前
C语言零基础入门:循环控制与数据类型详解
c语言·数据结构·算法
默_笙19 小时前
❗ 点击计数按钮,为什么"峨眉队"也跟着重新渲染?React.memo 说:我记住了
前端·javascript
日拱一卒的小田20 小时前
ZYNQ学习笔记3-ZYNQ的IIC控制器1
笔记·单片机·学习
名字还没想好☜20 小时前
Next.js 用 Server Components 直连数据库:去掉 API 层的边界,和三条别踩的安全红线
前端·javascript·数据库·安全·react·next.js
晚风醉蝶20 小时前
1-6-插入排序-InsertionSort
java·数据结构·排序算法
Tyler_TXZ21 小时前
C++C语言之——二叉树
c语言·开发语言·数据结构·c++·二叉树
Tisfy21 小时前
LeetCode 3090.每个字符最多出现两次的最长子字符串:二重循环 / 滑动窗口
算法·leetcode·字符串·题解·模拟·双指针·滑动窗口