js趣味算法思想

随意的前言

好久都没有写文章啦,React系列的文章还差一篇,但是感觉讲+写已经很腻了,所以先放一放,换一下口味吧!

今天我们来看看算法在实际问题中的应用,还是很有意思的哇~~~

对撞指针

思想:对撞指针的意思就是有两个指针,一个从开头,一个从结尾,两个指针分别++,--直到碰撞

这个思想可以解决什么问题呢?

题目:leedcode 167

给定一个从小到大有序的数组,从数组里找到两个数字可以等于target,并返回索引。

即:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]

分析:这道题可以直接用查找的方法,一层层循环去找。但是这样做时间复杂度为O(n2),而且完全没有利用到我们这个数组有序的特性。

更好的解法是:两个指针,分别从两边去找,相加>target,右边指针--前移,如果<target,左边指针++前移,一直到这两个指针碰撞,如果找到结果可以返回相应的索引。

代码实现:

var twoSum = function(nums, target) {
    var left = 0;
    var right = nums.length - 1 ;
    // 对撞的循环条件:左边指针小于右边指针
    while(left < right ) {
        if(nums[left] + nums[right] === target) {
            return [left, right]
        } else if(nums[left] + nums[right] > target ) {
            right--;
        } else {
            left++;
        }
    } 
};

滑动窗口

思想:

有两个指针构成一个区间,通过往同一个方向不停的移动,来找到满足条件的区间。

滑动窗口关键的是想想初始时候,两个指针在哪,在滑动的时候,两个指针基于什么条件移动,移动后的位置又在哪里。

下面来分析一个题目来看看如何用这个思想。

题目:leedcode 209

给定一个整形数组和一个数字s,找到数组中最短的一个连续子数组,使得连续子数组的数组和sum >= s,返回这个最短的连续子数组的长度值。

即:

Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2

分析:这里依旧可以采取暴力解法,找出所有的子数组,再分别相加求解。但是这里介绍更好的解法。

这里可以看到由于需要找连续的子数组,所以依旧可以设置两个指针,往同一方向移动。

如果两个指针中间的值加起来>sum的时候,记录此时数组的长度,接着左指针移动,减小sum的值 ;

如果< sum的话,右指针移动扩大范围。

最后返回最短的长度值。

代码实现:

/**
 * @param {number} s
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(s, nums) {
  var left = 0;
  var right = -1; // right 的起始位置很重要,这里选择-1 [left, right]这个区间刚开始是没有值的
  var tmpSum = 0;
  var minLength;

  // 循环停止的条件是左指针小于长度
  while (left < nums.length - 1) {
    if(tmpSum < s) {
      // 这里要注意边界的处理,当右指针移动到最后一个元素的时候结束
      if(right >= nums.length -1) {
        return minLength || 0;
      }
      right ++;
      // 这里tmpSum的计算也很巧妙,直接用累加的方式,节省计算量
      tmpSum = tmpSum + nums[right]
    } else {
      var tmp = right - left + 1;
      if(minLength) {
        if(tmp < minLength) {
          minLength = tmp;
        }
      } else {
        minLength = tmp;
      }
      // 左边指针移动减少sum的值
      tmpSum = tmpSum - nums[left];
      left ++;
    } 
  }
  if(!minLength) {
    return 0;
  }
  return minLength;
};

查找

这里先介绍两种数据结构 Set Map,不了解的同学先自行学习一下,其实很简单,Set类型就是只有key的一种数据结构,而Map类型有key,value。

而在JS中,Object类型基本跟Map类型的一样使用,但是还是有些不同的,也可以在这边文章里了解不同。

接下来通过具体的例子来看看如何使用它们。

题目:leedcode 1

这个问题跟开头的问题一样,给定一个数组numbers,从数组里找到两个数字可以等于target,并返回索引。

即:

Input: numbers = [2,7,11,15], target = 9  Output: [1,2]

分析:

除了暴力的解法,我们还可以用刚刚介绍的对撞指针的思路,先给它排序,在使用对撞指针,但是我们这里由于要返回索引,所以还要记录排序前的索引。其实这个思路也是有点麻烦的。

这里在介绍巧妙查找表的思路:

我们可以先定义一个Object类型的数据结构obj,它的key为target - numbers[i](比如数组第一项为2),value为索引。然后每次都看看obj[numbers[i]] 是否存在,如果存在,那我们就找到了这样的一组数据,返回当前索引以及obj[numbers[i]]。

代码实现:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
   var obj = {};

  for(var i=0; i< nums.length;i++) {
    const item = nums[i];
    if(obj[item] >= 0) {
      return [obj[item], i]
    } else {
      obj[target - item] = i;
    }
  }
};

面试中常考的数组去重的问题,也可以借助Object的查找思路,可以自行练习。

总结

因为在公司有后台处理数据,所以总觉得算法跟前端没有太大的关系,在看React源码的时候,里面使用了深度查找的思想。所以我觉得学好算法对我们还是很重要的。后面接着~

本文对你有帮助的话,点个赞鼓励一下作者呗 (੭ु≧▽≦)੭ु

原文https://zhuanlan.zhihu.com/p/46223775

猜你喜欢

转载自blog.csdn.net/sinat_17775997/article/details/88061589
今日推荐