在做 Largest Number 这道题之前,我对 sort 方法的用法是非常自信的。我很清楚不传比较因子的排序会根据元素字典序(字符串的UNICODE码位点)来排,如果要根据大小排序,需要传入一个比较函数。

先来看这道题,给你一个数组,让你把数组元素拼接起来,求能拼得的最大的数。如果只有两个数字 a 和 b,如何拼?很明显比较 abba 两个数的大小,所以这道题首先需要对数组做一次排序。刷刷写下如下代码:

nums.sort(function(a, b) {
  return (b + '' + a) > (a + '' + b);
});

因为 baab 位数相同,我觉得根据字典序即可比较大小,提交,221 组数据跪在了 201 组。我开始怀疑算法的正确性,直到无意中把比较函数改了下,便 AC 了:

nums.sort(function(a, b) {
  return (b + '' + a) - (a + '' + b);
});

这真的有区别么?印象中 c++ 中调用 STL 的 sort 函数,在比较函数中一直用的 < 以及 > 啊。我承认我以前从没有留意过。

我们把问题简化,先来看以下代码:

var largestNumber = function(nums) {
  nums.sort(function(a, b) {
    return a - b;
  });

  return nums;
};

console.log(largestNumber([41,32,81,97,99,91,90,63,76,76,67]));
// [32, 41, 63, 67, 76, 76, 81, 90, 91, 97, 99]

这是一次升序排序,结果完美,那么,为什么能得到这样的结果,有思考过 return a - b 的意思么?

如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。记 a 和 b 是两个将要被比较的元素:

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。

上面的的代码其实可以扩写成这样:

var largestNumber = function(nums) {
  nums.sort(function(a, b) {
    if (a - b > 0)
      return 1; // a 比 b 大,b 排到 a 前
    else if (a - b < 0)
      return -1;  // a 比 b 小,a 排到 b 前
    else
      return 0; // a 和 b 一样大,a 和 b 相对位置不变
  });

  return nums;
};

仔细想想,这样便是一个升序排列。

再来看错误写法:

var largestNumber = function(nums) {
  nums.sort(function(a, b) {
    return a > b;
  });

  return nums;
};

console.log(largestNumber([41,32,81,97,99,91,90,63,76,76,67]));
// [91, 41, 32, 63, 67, 76, 76, 81, 90, 97, 99]

其实可以扩写为:

var largestNumber = function(nums) {
  nums.sort(function(a, b) {
    if (a > b)
      return 1; // true 隐式转换为 1; b 排到 a 前
    else
      return 0; // false 隐式转换为 0; 相对位置不变
  });

  return nums;
};

仔细想想,明显有问题。a > b 时 b 排到 a 前没有问题,a < b 时位置不变,这就不对了。如果 a < b 时 return -1,让 a 排到 b 前,就对了。所以这样写也是没问题的:

var largestNumber = function(nums) {
  nums.sort(function(a, b) {
    if (a > b)
      return 1;
    else
      return -1;
  });

  return nums;
};

当然,a === b 这个条件可以随意归到 a > b 或者 a < b 那,也可以拎出来独立,以上代码我是归到 a < b 那了。

另外还需要注意的一点是,比较函数中的 a 和 b 参数,在数组中的位置是任意的,并不是 a 前 b 后。这里我写了段测试代码:

var largestNumber = function(nums) {
  nums.sort(function(a, b) {
    console.log(a, b);
    console.log(nums.concat());
    return a - b;
  });

  return nums;
};

console.log(largestNumber([41,32,81,97,99,91,90,63,76,76,67]));

结果很明显:

最后勉强回忆起 C++ 中的 sort 的比较函数返回的是一个 bool 值,而 JavaScript 比较函数能返回三个值,跟 C++ 中的 qsort 类似?实在回忆不起来也不想回忆了。

本题完整代码可以移步 https://github.com/hanzichi/leetcode/tree/master/Algorithms/Largest%20Number。PS:还有一个坑,拼起来的字符串需要去前导 0。

JavaScript中sort方法的一个坑(leetcode 179. Largest Number)的更多相关文章

  1. leetcode 179. Largest Number 、剑指offer33 把数组排成最小的数

    这两个题几乎是一样的,只是leetcode的题是排成最大的数,剑指的题是排成最小的 179. Largest Number a.需要将数组的数转换成字符串,然后再根据大小排序,这里使用to_strin ...

  2. [LeetCode] 179. Largest Number 最大组合数

    Given a list of non negative integers, arrange them such that they form the largest number. Example ...

  3. [leetcode]179. Largest Number最大数

    Given a list of non negative integers, arrange them such that they form the largest number. Input: [ ...

  4. Java 特定规则排序-LeetCode 179 Largest Number

    Given a list of non negative integers, arrange them such that they form the largest number. For exam ...

  5. leetcode 179. Largest Number 求最大组合数 ---------- java

    Given a list of non negative integers, arrange them such that they form the largest number. For exam ...

  6. Java for LeetCode 179 Largest Number

    Given a list of non negative integers, arrange them such that they form the largest number. For exam ...

  7. [LeetCode] 179. Largest Number 解题思路

    Given a list of non negative integers, arrange them such that they form the largest number. For exam ...

  8. LeetCode 179 Largest Number 把数组排成最大的数

    Given a list of non negative integers, arrange them such that they form the largest number.For examp ...

  9. Leetcode 179 Largest Number 贪心

    此题主要是讲给你一组数,如何将数连在一起能得到最大值(最小值反之),注意局部最优,就是说如果 123 234两个连在一起怎么样最大,显然是234123比123234大,对于3个数我们可以找到类似的性质 ...

随机推荐

  1. (ios) 屏幕触摸总结

    1  屏幕触控实现(单击 双击) [self becomeFirstResponder]; //允许多点互动 self.view.multipleTouchEnabled=TRUE; 实现事件部分 # ...

  2. maven依赖本地非repository中的jar包-依赖jar包放在WEB-INF/lib等目录下的情况客户端编译出错的处理

    MAVEN 今天在使用maven编译打包一个web应用的时候,碰到一个问题: 项目在开发是引入了依赖jar包,放在了WEB-INF/lib目录下,并通过buildpath中将web libariary ...

  3. ln

    文件描述符是相对进程而言的,一个文件可以有多个文件描述符,但只有一个inode,inode一样就是同一个文件,文件名不同也是同一个 硬链接 两个文件是指向同一个存储区,inode号一样,并没有开辟新的 ...

  4. Linux目录操作

    mkdir() #include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mod ...

  5. subversion-1.8.5 windows install dist

    python build\win32\make_dist.py subversion-1.8.5 d:/rapm

  6. 双核CPU,跑程序会报rcu_sched_state detected stalls on CPUs/tasks 错误

    有一份SDK,之前跑在PPC405EX上没问题。最近换平台,CPU使用了PowerPC的P1020,双核。linux版本也升级到了3.0.48版本。升级之后出现了一个问题:SDK里面的程序跑一段时间之 ...

  7. Docker+OpenvSwitch搭建VxLAN实验环境

    一.概述                                                    1.环境:我这里是2台linux机器(host1和host2),发行版是kali2.0, ...

  8. Windows Azure 虚拟机的IP地址操作

    Windows Azure上的一个虚拟机对应两个IP地址,VIP和DIP. VIP,公网IPv4地址,动态分配.虚拟机停止(deallocate,在管理控制台上关机或者使用PowerShell关机)后 ...

  9. C#迭代重载等

    迭代器 迭代器是作为一个容器,将要遍历的数据放入,通过统一的接口返回相同类型的值 迭代器代码使用 yield return 语句依次返回每个元素.yield break 将终止迭代 类中实现多个迭代器 ...

  10. cdoj 1489 老司机采花

    地址:http://acm.uestc.edu.cn/#/problem/show/1489 题目: 老司机采花 Time Limit: 3000/1000MS (Java/Others)     M ...