起因
最近面试web全栈开发工程师
岗位,接触到一个算法题,觉得很考验分析能力并且在实际中是有一定作用的算法,因此分享出来跟大家探讨。
题目
根据运营需求,你要为我们的数值发布系统增加一项数字输入框校验功能。我们通常会对一些数字输入进行大小限制。
比如要求输入的值必须在300 - 347
之间(包括300
和347
)。聪明的你发现,有时你可以不必等用户输入完就知道他的输入是否非法的了。
比如,上面这种情况,当用户输入37
时,肯定他的输入就是非法的了。
现在你需要用程序来做这件事。
输入:
第一行为输入框的下界
第二行为输入框的上界
第三行为一些用逗号分割的整数,这些整数作为用户输入的数字
输出:
仅有一行,为一些用逗号分割的字符串。
每个字符串对应一个用户输入的数字,如果用户输入为非法则输出INVALID
,否则输出VALID
输入约束
上下界均位于[1, 2000000000]
之间,且下界小于等于上界,第三行的数字个数位于[1, 50]
之间,且每个数字也位于[1, 2000000000]
之间
举例1:
输入 300
347
37
输出 INVALID
举例2:
输入 310
320
3,31,317,3174,310,320
输出 VALID,VALID,VALID,INVALID,VALID,VALID
解释:前3
个是输入317
时的顺序输入,所以都是合法的。最后2
个时上界和下界,也是合法的
题目分析
- 输入大于上限直接返回
INVALID
- 输入在下限和上限之间,直接返回
VALID
只有输入小于下限的情况,才会产生校验,因此代码重点在于这一步
- 上限和下限数字位数相差1位以上,比如下限31是两位数, 上限7001是四位数,因为输入是小于下限31的,又因为上下限中间可以包含全部的三位数字,三位数字都是符合条件的,因此直接返回
VALID
- 上限和下限数字位数相等的情况,只需要把上下限数字缩短到和输入数字一样的长度(从右边去除),这时输入必须在缩短后的上下限之间,才能返回
VALID
,否则你在输入之后无论怎么补充数字都无法保证在上下限之间。 上限和下限数字位数正好相差1位的情况
- 下限首位小于上限首位,比如下限
50
,上限618
,又因为输入小于50
,因此你在输入后面随便加一位都大于50
小于618
,直接返回VALID
- 下限首位大于等于上限首位,同样把上下限数字缩短到和输入数字一样的长度(从右边去除),这时候你必须保证输入大于等于缩短后的下限,或者小于等于缩短后的上限(此时缩短后的下限 > 缩短后的上限),才能返回
VALID
,否则你在输入后再次添加任何数字都是不合法的
- 下限首位小于上限首位,比如下限
- 上限和下限数字位数相差1位以上,比如下限31是两位数, 上限7001是四位数,因为输入是小于下限31的,又因为上下限中间可以包含全部的三位数字,三位数字都是符合条件的,因此直接返回
- 其他情况,一律返回
INVALID
代码实现
const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);
let min = 0;
let minLen = 0;
let max = 0;
let maxLen = 0;
let strArr = null;
let outputArr = [];
let index = 0;
rl.on('line', function(line) {
if (index === 0) {
min = parseInt(line);
if (min < 1 || min > 12000000000) {
console.log('输入有误!');
rl.close();
}
minLen = line.length;
}
if (index === 1) {
max = parseInt(line);
if (max < 1 || max > 12000000000) {
console.log('输入有误!');
rl.close();
}
if (min > max){
console.log('上界不能小于下界!');
rl.close();
}
maxLen = line.length;
}
if (index === 2) {
strArr = line.split(',');
const len = strArr.length;
if (len < 1 || len > 50) {
console.log('输入有误!');
rl.close();
}
for (const str of strArr) {
const num = parseInt(str);
if (num < 1 || num > 12000000000) {
console.log('输入有误!');
rl.close();
}
// 大于上限直接返回INVALID
if (num > max) {
outputArr.push('INVALID');
continue;
}
// 大于等于下限且小于等于上限直接返回VALID
if (num <= max && num >= min) {
outputArr.push('VALID');
continue;
}
// 小于下限的情况
// 上下限位数相差1以上,直接返回VALID
if (maxLen - minLen > 1) {
outputArr.push('VALID');
continue;
}
// 上下限位数相等的情况,即maxLen = minLen;
const len = str.length;
const offsetMin = String(min).slice(0, len);
const offsetMax = String(max).slice(0, len);
if (maxLen === minLen && str >= offsetMin && str <= offsetMax) {
outputArr.push('VALID');
continue;
}
// 上下限位数相差1位的情况
if (maxLen - minLen === 1) {
// 下限首位小于上限首位
if (String(min)[0] < String(max)[0]) {
outputArr.push('VALID');
continue;
}
// 下限首位大于等于上限首位
if (str >= offsetMin || str <= offsetMax ){
outputArr.push('VALID');
continue;
}
}
// 其他情况
outputArr.push('INVALID');
}
console.log(outputArr.join(','));
rl.close();
}
index++;
}).on('close',function(){
// It's important to exit, otherwise the execution will time out
process.exit(0);
});
总结
此代码跑通了测试端全部测试用例并且没有超出响应时间限制,各位同学可以做个参考,也欢迎有其他更好思路的朋友留言分享。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。