Back
Featured image of post JavaScript | leetcode

JavaScript | leetcode

你追,你逃,面对leetcode插翅难逃,主要放一些杠上了题目逐步改进的过程

背景

放些卡的题目,和逐步改进的思路和策略以及测试结果。

3sum

leetcode 3sum

solution 1: Time Limit Exceeded

315 / 318 test cases passed. 折戟沉沙的数据集地址

本地跑了下,用时50-60s,最终得到的数据个数是16258,考虑到这个solution 1 毕竟通过了绝大部分测试集,姑且当作是这个数据集的正确个数。

  var threeSum = function (nums) {
    let result = [];// 用来返回最终结果
    let capture = [];// 存放数据的快照,用来排除相同组合。
    // 循环嵌套,第一个int
    for (let i = 0; i <= nums.length; i++) {
      // 循环嵌套,第二个int
      for (let j = 0; j <= nums.length; j++) {
        // i,j的value可以相等,但是index是不能一样
        if(i != j ){
          // 最后一个int是 i,j对应数据的负数
        let kValue = 0 - nums[i]-nums[j];
        // 找到k的index
        let k = nums.indexOf(kValue);
        // k必然是存在,且不能和i,j相同
        if (k>=0 && k != i && k!=j){
          // 找到一个子集
          let item = [nums[i],nums[j],nums[k]];
          // 对子集进行排序和tostring操作,存作快照
          if(capture.indexOf(item.sort().join(",")) == -1){
            // 且快照中不存在该string,才进行push。
            capture.push(item.sort().join(","));
            // 同时作为一个真 子集,push到最后要返回的array中。
            result.push(item);
          }
        }
      }
    }
  }
  // 全部暴力循环后,返回。
  return result;
}

通过now-mdn可以测试每一步所花费的时间。通过一些测试,会发现问题是出在for循环上,因此思路要换换。

solution 2: Runtime Error

然后我开始考虑,要不要试着当做数学题来看。然后也报错了,淦。但是数据个数和上面一样。折在同一个数据集,但是本地能跑出来,时间是10s的样子。 而且跑出来的数据集个数也是一样的:16258

submissions/detail

思路倒是也简单,就是先进行sort

  1. 作为一个全是数字的数组,需要挑选3个数字达到和值为0的结果,那么就是3种情况:【负数,0,正数】,【负数,正数,正数】,【负数,负数,正数】, 当且仅当0有三个以上,可以多一个特殊情况【0,0,0】
  2. 决定先把排序后arr中第一个0和最后一个0的位置找到,这样可以知道有没有特殊情况。
  3. 先整体来说,【负数,正数,正数】,【负数,负数,正数】这两种情况是有没有0,都会需要做的。所以考虑抽成一个函数。
  4. 开始判断0的个数,如果是>=3个,就先把特殊【0,0,0】放进去。
  5. 只要有0,【负数,0,正数】这样的就需要去找找看。
  6. 有0无0,影响的其实是sort后的arr的正负数index区间。因此再次调用函数。
  var threeSum = function (nums) {
    let result = [];
    // 这个函数是在a中找两个数,再确认他们和的相反数是否在b中
    function FindOut(a, b) {

      var c2a = a.flatMap( //从参数a这个arr入手,排列组合,从里面选2个(index)数,就会变成一个新的arr
        (v, i) => a.slice(i + 1).map(w => v + "," + w + "," + (v + w)) //这个可以得出三个值,“加数1,加数2,加数1+加数2”
      );
      // 做成了["1,1,2",“1,2,3”...]的原因就是为了去重,因为数组直接去重不行,也不知道为啥,字符串就行。
      addend = [... new Set(c2a)];
      // 然后会考虑,“num1,num2,num3”split过,拿到没有“,”的,再变为int
      for (let i in addend) {
        let item = addend[i].split(",");
        let last = -parseInt(item[2]);
        if (b.find(element => element == last)) {
          result.push([parseInt(item[0]), parseInt(item[1]), last]);
        }
      }
    };

    nums.sort(function (a, b) { return a - b });// 将nums 按着int从小到大排序。这个用时大概是1-2ms,非常小,也就是build-in 函数只作一层其实非常快。

    var zero0 = nums.indexOf(0); // 找到第一个0的index
    var zero1 = nums.lastIndexOf(0); //最后一个0 的index

    //step 1 ,当数组没有0的时候,其实只用考虑:【负数,正数,正数】,【负数,负数,正数】这两种情况。
    if (zero0 === -1) {
      var minPositiveIndex = nums.findIndex(element => element > 0); // 返回的是该正数的index,如果找不到,那么这个值会被定成-1
      if (minPositiveIndex != -1) { // 整个array确实有正数:
        //截取nums array的正整数集合:
        var allPositives = nums.slice(minPositiveIndex); //正数
        var allNegatives = nums.slice(0, minPositiveIndex); // 负数
        FindOut(allPositives, allNegatives);
        FindOut(allNegatives, allPositives);
      };
    }
    // step 1 over  
    // step 2
    if (zero0 != -1 && zero1 != -1 && zero1 - zero0 >= 2) { //前后同时存在0,且至少有3个0,
      result.push([0, 0, 0]);
    };
    // step 2 over

    // step 3 when nums have 0.
    if (zero0 != -1 && zero1 != -1) { //也许是1,2,3....个0,但是不管多少个0,在【负数,0,正数】的场景下都是一个0

      var allNegatives = nums.slice(0, zero0);//所有的负数array
      var allPositives = nums.slice(zero1 + 1);//所有的正数array

      // step 3.1考虑处理【负数,0,正数】这个集合
      // 由于这一步只考虑[-,0,+] 这样的相反数组合,因此会想去重处理一下:
      allNeSingle = [...new Set(allNegatives)];
      allPoSingle = [...new Set(allPositives)];
      for (let i in allNeSingle) { // 对于【负数,0,正数】这样的组合,找一边就可以了。
        let lastIndex = allPoSingle.indexOf((-allNeSingle[i])); //在正数集合里找,负数,对应相反数的index,
        if (lastIndex != -1) { // 找到了index

          let item = [allNeSingle[i], 0, allPoSingle[lastIndex]];
          result.push(item);// store the item as a reslut element

        }
      };
      // step 3.1 over

      // step 3.2 start
      // 【负数,正数,正数】,【负数,负数,正数】,在有0的情况下去截取。
      FindOut(allPositives, allNegatives);
      FindOut(allNegatives, allPositives);
      // step 3.2 over

    };
    // step3 完结。

    return result;
  }

搜了下,这个错误一般都是内存用太多,然后又搜了下js咋看内存消耗:Analyze runtime performance

就用太多了,整整430MB,真可怕。看了眼答案人家都是50MB左右。

淦,忧郁了,暂时不做题了

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy