头图

起因

最近面试web全栈开发工程师岗位,接触到一个算法题,觉得很考验分析能力并且在实际中是有一定作用的算法,因此分享出来跟大家探讨。

题目

根据运营需求,你要为我们的数值发布系统增加一项数字输入框校验功能。我们通常会对一些数字输入进行大小限制。
比如要求输入的值必须在300 - 347之间(包括300347)。聪明的你发现,有时你可以不必等用户输入完就知道他的输入是否非法的了。
比如,上面这种情况,当用户输入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个时上界和下界,也是合法的

题目分析

  1. 输入大于上限直接返回INVALID
  2. 输入在下限和上限之间,直接返回VALID
  3. 只有输入小于下限的情况,才会产生校验,因此代码重点在于这一步

    • 上限和下限数字位数相差1位以上,比如下限31是两位数, 上限7001是四位数,因为输入是小于下限31的,又因为上下限中间可以包含全部的三位数字,三位数字都是符合条件的,因此直接返回VALID
    • 上限和下限数字位数相等的情况,只需要把上下限数字缩短到和输入数字一样的长度(从右边去除),这时输入必须在缩短后的上下限之间,才能返回VALID,否则你在输入之后无论怎么补充数字都无法保证在上下限之间。
    • 上限和下限数字位数正好相差1位的情况

      • 下限首位小于上限首位,比如下限50,上限618,又因为输入小于50,因此你在输入后面随便加一位都大于50小于618,直接返回VALID
      • 下限首位大于等于上限首位,同样把上下限数字缩短到和输入数字一样的长度(从右边去除),这时候你必须保证输入大于等于缩短后的下限,或者小于等于缩短后的上限(此时缩短后的下限 > 缩短后的上限),才能返回VALID,否则你在输入后再次添加任何数字都是不合法的
  4. 其他情况,一律返回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);
});

总结

此代码跑通了测试端全部测试用例并且没有超出响应时间限制,各位同学可以做个参考,也欢迎有其他更好思路的朋友留言分享。


小磊
352 声望884 粉丝

以一颗更加开放,更加多元,更加包容的心走进别人的世界