简单又有趣的JavsScript 算法

JavsScript 算法

一些简单又有趣的jacaScript算法,让锈逗的脑壳转起来。
更多JavaScript 算法与数据结构

排序

冒泡排序

function bubbleSort(arr) {
  var i = arr.length-1;  //初始时,最后位置保持不变
  while ( i> 0) {
      var pos= 0; //每趟开始时,无记录交换
      for (var j= 0; j< i; j++)
          if (arr[j]> arr[j+1]) {
              pos= j; //记录交换的位置
              var tmp = arr[j]; arr[j]=arr[j+1];arr[j+1]=tmp;
          }
      i= pos; //为下一趟排序作准备
   }
   return arr;
}
冒泡排序

选择排序

function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    for (var i = 0; i < len - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {     //寻找最小的数
                minIndex = j;                 //将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}

选择排序

插入排序

function binaryInsertionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        console.time('二分插入排序耗时:');

        for (var i = 1; i < array.length; i++) {
            var key = array[i], left = 0, right = i - 1;
            while (left <= right) {
                var middle = parseInt((left + right) / 2);
                if (key < array[middle]) {
                    right = middle - 1;
                } else {
                    left = middle + 1;
                }
            }
            for (var j = i - 1; j >= left; j--) {
                array[j + 1] = array[j];
            }
            array[left] = key;
        }
        console.timeEnd('二分插入排序耗时:');

        return array;
    } else {
        return 'array is not an Array!';
    }
}
插入排序

快速排序

var quickSort = function(arr) {
  if (arr.length <= 1) { return arr; }
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = arr.splice(pivotIndex, 1)[0];
  var left = [];
  var right = [];
  for (var i = 0; i < arr.length; i++){
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat([pivot], quickSort2(right));
};
快速排序

归并排序

  function mergeSort(arr){
  var len = arr.length
  if(len < 2){
    return arr
  }
  var middle = Math.floor(len/2)
  var left = arr.slice(0,middle)
  var right = arr.slice(middle)
  return merge(mergeSort(left),mergeSort(right))
}

function merge(left,right){
  var result = []
  while (left.length && right.length){
        if(left[0]<= right[0]){
          result.push(left.shift())
        }else{
          result.push(right.shift())
        }
  }
  while(left.length)
    result.push(left.shift())
  
  while(right.length)
    result.push(right.shift())
  return result
}

遍历dom

<div id="id">
    <div id="id1">
          <div id="id1.1"></div>
          <div id="id1.2"></div>
          <div id="id1.3"></div>
    </div>
    <div id="id2">
          <div id="id2.1"></div>
          <div id="id2.2"></div>
          <div id="id2.3"></div>
     </div>
     <div id="id3">
          <div id="id3.1"></div>
          <div id="id3.2"></div>
          <div id="id3.3"></div>
      </div>
 </div>

深度优先

function deepTraversal(node,nodelist=[]){
  if(node !== null){
    nodelist.push(node)
    let children = node.children
    for(let i= 0;i<children.length; i++){
      deepTraversal(children[i],nodelist)
    }
  }
  return nodelist
}

0: div#id
1: div#id1
2: div#id1.1
3: div#id1.2
4: div#id1.3
5: div#id2
6: div#id2.1
7: div#id2.2
8: div#id2.3
9: div#id3
10: div#id3.1
11: div#id3.2
12: div#id3.3

广度优先

function widthTraversal (node){
  let nodes = []
  let stack = []
  if(node){
    stack.push(node)
    while(stack.length){
      let item = stack.shift()
      let children = item.children
      nodes.push(item)
      for(let i=0; i<children.length;i++){
        stack.push(children[i])
      }
    }
  }
  return nodes
}

0: div#id
1: div#id1
2: div#id2
3: div#id3
4: div#id1.1
5: div#id1.2
6: div#id1.3
7: div#id2.1
8: div#id2.2
9: div#id2.3
10: div#id3.1
11: div#id3.2
12: div#id3.3

二叉树

41558428226_.pic.jpg
  var tree = {
    value: 1, left: {
      value: 2, left: {
        value: 4
      }
    },
    right: {
      value: 3,
      left: {
        value: 5, left: {
          value: 7
        },
        right: {
          value: 8
        }
      },
      right: {
        value: 6
      }
    }
  }
  var preOrder = function (node) {
    if (node) {
      console.log(node.value);
      preOrder(node.left);
      preOrder(node.right);
    }
  }
  var postOrder = function (node) {
    if (node) {
      postOrder(node.left);
      postOrder(node.right);
      console.log(node.value);
    }
  }
  var midOrder = function (node) {
    if (node) {
      midOrder(node.left);
      console.log(node.value);
      midOrder(node.right);
    }
  }

  preOrder(tree) // 1,2,4,3,5,7,8,6
  
  postOrder(tree) // 4,2,7,8,5,6,3,1
  
  midOrder(tree) // 4,2,1,7,5,8,43,6  

质数(千万2s)

function prime(n){
  let time = Date.now()
  let Memo = Array(n).fill(-1)
  let sqrt = Math.ceil(Math.sqrt(n))
  let res = []
  for(let i = 2;i<=sqrt;i++){
    if(Memo[i]===1) continue
    for(let j=2;j<= n/i;j++){
      if(Memo[i*j] === -1){
        Memo[i*j] = 1
      }
    }
  }
  for(let i=2;i<=n;i++){
    Memo[i] === -1 && res.push(i)
  }
  console.log(Date.now()-time)
  return res
}
image.png

斐波那契数列(Fibonacci sequence)


function fibonacciClosedForm(position) {
 const topMaxValidPosition = 75;
 if (position < 1 || position > topMaxValidPosition) {
   throw new Error(`Can't handle position smaller than 1 or greater than ${topMaxValidPosition}`);
 }
 const sqrt5 = Math.sqrt(5);
 const phi = (1 + sqrt5) / 2;
 return Math.floor((phi ** position) / sqrt5 + 0.5);
}
// 动态规划
function fibonacciNth(n) {
 let currentValue = 1;
 let previousValue = 0;
 if (n === 1) {
   return 1;
 }
 let iterationsCounter = n - 1;

 while (iterationsCounter) {
   currentValue += previousValue;
   previousValue = currentValue - previousValue;
   iterationsCounter -= 1;
 }
 
 return currentValue;
}
// 递归
function fibonacciNth(n) {
 if(n<=0){
   return n
 }
 let Memo = []
 for(let i=0;i<=n;i++){
   Memo[i]= -1
 }
 return fib(n,Memo)
}
function fib(n,Memo){
 if(Memo[n] !== -1) return Memo[n]
 if(n<2) {
   Memo[n] = 1
 }else {
   Memo[n]=fib( n-1,Memo)+fib(n-2,Memo)
 }
 return Memo[n]
}
image.png

爬楼梯 一共10级楼梯,每次可以走一步或两步,求一共多少种走法

var fib = function (n){
  if(n == 1){
    return 1;
  }else if(n==2){
    return 2;
  }else if(n>2){
    return fib(n-1) + fib(n-2);
  }
}

细胞分裂 1个细胞,一个小时分裂一次,生命周期是3小时,求n小时后容器内,有多少细胞

function cellNumber(hour){
    let firstCycle = function (hour){
        if(hour===0){return 1;} //初始的那个细胞
        return firstCycle(hour-1)+secondCycle(hour-1)+thirdCycle(hour-1);
    }
    let secondCycle = function(hour){
        if(hour===0){return 0;} //一个小时之后才会生成
        return firstCycle(hour-1);
    }
    let  thirdCycle = function(hour){
        if(hour===0||hour===1){return 0;} //前两小时还没生成
        return secondCycle(hour-1);
    }
    return firstCycle(hour)+secondCycle(hour)+thirdCycle(hour)
}



el:2

第一周期(0h) 第二周期(1h) 第三周期(2h)
a(2) + b(2) + c(2)
a(1)+b(1)+c(1) + a(1) + b(1)
a(0)+a(1) + a(0) + a(1)
a(0)+a(0) + a(0) + a(0)
1 + 1 + 1 + 1

判断2次方数

function isPowerOfTwo(number){
    if (number < 1) {
        return false;
    }  
    return (number & (number - 1)) === 0;
}

素数检测

function trialDivision(number) {
    if (number % 1 !== 0) {
      return false;
    }
  
    if (number <= 1) {
      return false;
    }
  
    if (number <= 3) {
      return true;
    }
  
    if (number % 2 === 0) {
      return false;
    }
  
    const dividerLimit = Math.sqrt(number);
    for (let divider = 3; divider <= dividerLimit; divider += 2) {
      if (number % divider === 0) {
        return false;
      }
    }
  
    return true;
  }

整数拆分

拆分为因试和

n=1+f(n-1);
n=2+f(n-2);
·····
n=(n-1)+f(1);
n=n+f(0)

f(n)=f(n−1)+f(n−2)+……+f(1)+f(0)(其中f(0)=1) 公式①

数学公式推导:
f(n+1)=f(n)+f(n−1)+……+f(2)+f(1) 公式②

由②-①得
f(n+1)−f(n)=f(n)−f(0)

f(n+1)=2f(n)−1

f(n+1)−1=2[f(n)−1]

于是可以解得
f(n)=2^{(n−1)},n>=1

image.png

function integerPartition(number) {
  let res_num= 0
  let res = []
  let p = 0
  resolve(number)
  console.log("total num of res:",res_num)
  function resolve(number){
    if(number<=0){
      console.log(res.slice(0,p))
      res_num ++
    }
    for(let i=1;i<=number;i++){
      res[p] = i
      p++
      resolve(number-i)
      p--
    }
  } 
}
image.png

看输出可以发现,112,211,13,31,其实是重复的,其实我们只要保证,所以都按照由大到小排序就能保证不再重复,新加一个参数min_number,限制for循环的初始值,从而达到这个目的,思想跟前面排序的思想类似。

function integerPartition(number) {
  let res_num= 0
  let res = []
  let p = 0
  resolve(number,1)
  console.log("total num of res:",res_num)
  function resolve(number, min_number){
    if(number<=0){
      console.log(res.slice(0,p))
      res_num ++
    }
    for(let i=min_number;i<=number;i++){
      res[p] = i
      p++
      resolve(number-i,i)
      p--
    }
  } 
}
image.png

拆分为因试积

function integerPartition(number) {
  let res= []
  let num = 0
  let p = 0
  resolve(number,2)
  console.log("total num of res:",num)
  function resolve(number, min_number){
    if(number<2){
      num++
      console.log(res.slice(0,p))
    }
    for(let i = min_number;i<=number;i++){
      if(number%i==0)
        {
            res[p]=i;
            p++; 
            resolve(number/i,i);
            p--;        
        }
    }
  }
}
image.png

洗牌

function fisherYates(originalArray) {
  const array = originalArray.slice(0); //不改变原数据
  for (let i = (array.length - 1); i > 0; i--) {
    const randomIndex = Math.floor(Math.random() * (i + 1));
    [array[i], array[randomIndex]] = [array[randomIndex], array[i]];
  }
  return array;
}

幂集

回溯解决(不断将下一个元素添加到子集)

function powerset(arr){
    var ps = [[]];
    for(var i=0;i<arr.length;i++){
        for(var j=0,len=ps.length;j<len;j++){
            ps.push(ps[j].concat(arr[i]));
        }
    }
    return ps;
}

按位解决

1代表存在,0代表不存在

1/0 abc 子集
0 000 {}
1 001 {c}
2 010 {b}
3 011 {c,b}
4 100 {a}
5 101 {a,c}
6 110 {a,b}
7 111 {a,b,c}

组合求和

function combinationSumRecursive(
  chooseArr,
  sum,
  res = [],
  now = [],
  start = 0
) {
  if (sum < 0) return res
  if (sum === 0) {
    res.push(now.slice())
    return res;
  }
  for (let candidateIndex = start; candidateIndex < chooseArr.length; candidateIndex += 1) {
    const currentCandidate = chooseArr[candidateIndex]
    now.push(currentCandidate)
    combinationSumRecursive(
      chooseArr,
      sum - currentCandidate,
      res,
      now,
      candidateIndex
    )
    now.pop()
  }
  return res
}
image.png

雨水收集问题

image.png
function dpRainTerraces(terraces) {
  let waterAmount = 0;

  const leftMaxLevels = new Array(terraces.length).fill(0);
  const rightMaxLevels = new Array(terraces.length).fill(0);

  [leftMaxLevels[0]] = terraces;
  for (let terraceIndex = 1; terraceIndex < terraces.length; terraceIndex += 1) {
    leftMaxLevels[terraceIndex] = Math.max(
      terraces[terraceIndex],
      leftMaxLevels[terraceIndex - 1],
    );
  }

  rightMaxLevels[terraces.length - 1] = terraces[terraces.length - 1];
  for (let terraceIndex = terraces.length - 2; terraceIndex >= 0; terraceIndex -= 1) {
    rightMaxLevels[terraceIndex] = Math.max(
      terraces[terraceIndex],
      rightMaxLevels[terraceIndex + 1],
    );
  }

  for (let terraceIndex = 0; terraceIndex < terraces.length; terraceIndex += 1) {
    const currentTerraceBoundary = Math.min(
      leftMaxLevels[terraceIndex],
      rightMaxLevels[terraceIndex],
    );
    if (currentTerraceBoundary > terraces[terraceIndex]) {
      waterAmount += currentTerraceBoundary - terraces[terraceIndex];
    }
  }

  return waterAmount;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容

  • 概述 因为健忘,加上对各种排序算法理解不深刻,过段时间面对排序就蒙了。所以决定对我们常见的这几种排序算法进行统一总...
    清风之心阅读 694评论 0 1
  • 文章大纲:1.总体排序算法对比图2.9种排序算法介绍 冒泡排序 算法描述 冒泡排序是一个平均时间复杂度为O(n^2...
    柠檬乌冬面阅读 4,059评论 0 73
  • It's often said that happiness is achievedonce passion co...
    NapoleonHill阅读 1,015评论 0 2
  • 晚上,我宣布:今晚,我不想做饭了,老公,我们不吃了吧。先生说:好啊。 然后我就去给西西做了艾灸,晾衣服,拖地板,塞...
    秀琴sukin阅读 407评论 1 1
  • 刘琳焦点讲师班坚持第572天分享(2018/12/25) 今天难得到朋友的寻味茶社,度过了一个温馨的午后。...
    小溪与大海阅读 92评论 0 0