版本比较可以更优雅

59 阅读2分钟

在力扣上有一道经典的笔试题,比较两个版本号的大小,通常的解决思路就是将版本号拆分,然后逐个比较,最后写出来大概是下面这个鬼样子,虽然看起来没毛病,运行起来也没问题,但是就是不够骚气

function isVersionGreaterThan(version1: string, version2: string): boolean {
    // 分割版本号为各个部分
    const v1Parts: number[] = version1.split('.').map(Number);
    const v2Parts: number[] = version2.split('.').map(Number); 
    
    // 获取版本号的长度 
    const lenV1: number = v1Parts.length; 
    const lenV2: number = v2Parts.length; 
    
    // 循环比较各个部分 
    for (let i = 0; i < Math.max(lenV1, lenV2); i++) {
        const v1Part: number = i < lenV1 ? v1Parts[i] : 0;
        const v2Part: number = i < lenV2 ? v2Parts[i] : 0;
        
        if (v1Part < v2Part) {
            return false; 
        } else if (v1Part > v2Part) {
            return true; 
        } 
    }
    
    // 如果所有部分都相等,则版本号相等,此时也返回 false 
    return false; 
} 

// 测试 
const version1: string = "1.2.3"; 
const version2: string = "1.2.4"; 
const result: boolean = isVersionGreaterThan(version1, version2); console.log(result); // 输出 false

最近发现一个很骚的写法,思路也很惊奇。比较版本号通常是逐位比较,如果当前位的版本已经能比较出大小了,则可以直接返回比较结果,否则继续比较下一位直到遍历完所有位数。但是呢这太常规了,代码写得不骚气,如何才能涨薪呢,那怎么才能唬住接手的同事呢。下面这种方法,不需要使用循环遍历版本的每一位,通过生成器,每次迭代出一位版本号,然后比较。一个字

绝!

function* walk(version: string) {
  let part = '';
  const delimiter = ['.', '-'];

  for (let i = 0; i < version.length; i++) {
    const char = version[i];
    if (delimiter.includes(char)) {
      yield part;
      part = '';
    } else {
      part += char;
    }
  }
}

/**
 * 比较两个版本号
 * - v1 大于 v2 返回 `true`
 * - v1 小于等于 v2 返回 `false`
 * @param v1
 * @param v2
 * @returns boolean
 */
function compareVersion(v1: string, v2: string): boolean {
  const g1 = walk(v1);
  const g2 = walk(v2);
  while (true) {
    const n1 = g1.next();
    const n2 = g2.next();
    if (n1.value > n2.value) {
      return true;
    }
    if (n1.value < n2.value) {
      return false;
    }
    if (n1.done === n2.done && n1.done === true) {
      return false;
    }
  }
}

const v1 = '12.4.2';
const v2 = '12.4.1';

console.log(compareVersion(v1, v2)); // true