记录一些基础算法

开始补充一些算法和数据结构的知识

冒泡排序

const arr = [162, 6, 3, 8, 90, 234, 5, 7, 31, 45, 12, 1, 98, 23, 87, 40]
function sort(arr) {
  const len = arr.length - 1
  for (let x = 0, y = len; x < y; x++) {
    // 把第一个跟后面那个对比,如果比后面的数大,就交换位置,到最后就可以确定最大的数在最后
    // 也就是在 length 的位置
    // 在第一轮的时候,x=1,也就是遍历到倒数第二个就好,因为取到 i+1 的数
    for (let i = 0, l = len - x; i < l; i++) {
      const first = arr[i], second = arr[i+1]
      if (first > second) {
        [arr[i], arr[i+1]] = [second, first]
      }
    }
    // 假设没有第一层,最大的数已经在最后,那么第二轮就是要在剩下的数找到最大,并放到倒数第二位置
    // 也就是在 length-1 的位置
    // 此时 x=2,因为依然是当轮最后数(第二轮为length-1)的前一个
    // for (var i = 0, l = arr.length - 2; i < l; i++) {
    //  if (arr[i] > arr[i+1]) {
    //    [arr[i], arr[i+1]] = [arr[i+1], arr[i]]
    //  }
    // }
    // 第三轮 x=3
    // for (var i = 0, l = arr.length - 3; i < l; i++) {
    //  if (arr[i] > arr[i+1]) {
    //    [arr[i], arr[i+1]] = [arr[i+1], arr[i]]
    //  }
    // }
    // 第四轮 x=4
    // for (var i = 0, l = arr.length - 4; i < l; i++) {
    //  if (arr[i] > arr[i+1]) {
    //    [arr[i], arr[i+1]] = [arr[i+1], arr[i]]
    //  }
    // }
    // 所以循环个遍,就成了外面一层的循环
  }
  return arr
}
console.log(sort(arr))

二分法

就是在一个有序的序列中迅速找到要找的那个数的索引。一个一个遍历当然也可以找到,但是不确定性导致复杂度。
二分法就是中间砍一刀,这样数列就成了两半。看看中间值是不是,是那就刚好了。不是的话,判断目标数是在前一半还是后一半,如此这般的循环即可。

这种思想应该在现实生活中还是经常用到的,比如git bisect看看大佬的介绍)。
以及,让我想起以前 TVB 的《超级无敌掌门人》里面有个游戏叫“超级无敌开口中”,轮流在在100里面瞎说一个数,中了就受罚。特别是轮到说最后一个必中的数字时那种视死如归的神情,超搞笑。

function getRandomNum(numMin, numMax) {
  return Math.round( Math.random()*(numMax-numMin) + numMin )
}  
function getArr() {
  const arr = []
  for(let i = 1, l = 100; i <= l; i++) {
    arr.push(i)
  }
  return arr
}
// 随机生成 1 ~ 100 中的某数
const num = getRandomNum(1, 100)
// 生成 1 - 100 的数组
const arr = getArr()
function binarySearch(num, arr) {
  let start = arr.length
  let end = 0
  const getHalf = () => {
    let length = start + end
    return (length % 2 === 0) ? (length / 2) : (length + 1) / 2
  }
  // 取中值
  let half = getHalf()
  let current = arr[half]
  while (current !== num) {
    if (current > num) {
      start = half
    } else if (current < num) {
      end = half
    }
    half = getHalf()
    current = arr[half]
  }
  return half
}
const idx = binarySearch(num, arr)
console.log(idx, arr[idx], num)

斐波那契数列

具体的数学意义就不说了,我也不懂,总而言之是满足这样的一个数列:F(0)=0,F(1)=1,F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)

// 第一反应就是递归,最简单最明晰。但效率最低,其实就是每次算出来的值没存起来,导致每个 n 位的值传进去都要重新递归的算
function fibonacci(n) {
  if(n === 0 || n === 1) {
    return n
  }
  return fibonacci(n-1) + fibonacci(n-2)
}
// 改进一些,是个数列自然就可以用个数组来存
// 把之前获得 n 位的值存起来,下次要拿就直接取就好
function fibonacci2(n) {
  if(n === 0 || n === 1) {
    return n
  }
  const arr = [0, 1]
  for(let i = 2; i <= n; i++) {
    arr[i] = arr[i-1] + arr[i-2]
  }
  return arr[n]
}
// 改进一些,其实每次都是需要上两位就可以了,不需要用整个数组来存全部
function fibonacci3(n) {
  if(n === 0 || n === 1) {
    return n
  }
  let lastOne = 1 // n-1
  let lastTwo = 0 // n-2
  for(let i = 2; i <= n; i++) {
    var current = lastOne + lastTwo
    // n-2 和 n-1 分别获取后一位的值
    lastTwo = lastOne
    lastOne = current
  }
  return current
}
// 第一种递归的方法,在浏览器 40 以后基本快跑不出来了
// 第三种还是比第二种快那么些许
console.time('fibonacci')
console.log(fibonacci(40))
console.timeEnd('fibonacci')