js 常见算法(三)

92 阅读3分钟

查找算法常用的顺序查找与二分查找,算法思想动态规划、贪心算法、回溯算法……


一 查找算法

查找,根据给定的某个值,在给定的表中确定一个等于给定值的数据元素或记录。

1. 顺序查找

顺序查找,遍历数据元素,直到找到对应的元素,找不到,返回 -1。适合于存储结构为顺序存储或链接存储的线性表,实用于无序和有序数组。

顺序查找.png

function search (arr, value) {
  for(let i = 0,len = arr.length; i < len; i ++) {
    if (arr[i] === value) {
      return i;
    }
  }
}
search([12, 4, 3, 2, 5, 84, 34, 52, 42, 45, 6, 7, 86, 68, 67], 2) // 返回索引 3

2. 二分查找

二分查找, 在有序数组中不断取中间值,直到找到对应的元素,找不到,返回 -1。只针对有序数组实用。

二分查找.png

const arr = [2, 3, 4, 5, 6, 7, 12, 34, 42, 45, 52, 67, 68, 84, 86];

function binarySearch (arr, value) {
  if (arr.length <= 0) {
    return -1;
  }
  let start = 0;
  let end = arr.length - 1;
  while(start <= end) {
    // 不停的取中间值
    let mid = Math.floor((start + end) / 2);
    // 找到元素后,返回索引
    if (value === arr[mid]) {
      return mid;
    }else if (value < arr[mid]) {
      // 当前值 大于 要查找的值
      end = mid - 1;
    } else if (value > arr[mid]) {
      // 当前值 小于 要查找的值
      start = mid + 1;
    }
  }
  // 找不到,返回-1
  return -1;
}

console.log(binarySearch([2, 3, 4, 5, 6, 7, 12, 34, 42, 45, 52, 67, 68, 84, 86], 4));

二 动态规划

动态规划,为运筹学的一个分支,意为通过将大问题分解为小问题求最优解,从而得到大问题的结论。

动态规划并不是一种特殊算法,而是对解最优化问题的一种途径、一种方法。并没有一种标准的数学表达式和明确的解题方法,由于各种问题性质不同,确定最优解的条件也不相同,不存在一种万能的动态规划算法。

能采用动态规划求解的问题的一般要具有3个性质:

  • 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。

  • 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

  • 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

示例:

动态规划示例.jpg

如上图,用动态规划解决问题如下:

(1) 登上第一台阶:只有一个方法

  • 1

(2) 登上第二台阶:有两种方法

  • 1 - 1
  • 2

(3) 登上第三台阶:有三种方法

  • 1 - 1 - 1
  • 1 - 2
  • 2 - 1

(4) 登上第四台阶:有五种方法

  • 1 - 1 - 1 - 1
  • 1 - 1 - 2
  • 1 - 2 - 1
  • 2 - 1 - 1
  • 2 - 2

依次类推……

// 爬楼梯方法  ---- 递归版本
function climbStairs (n) {
  // 如果当前是 第 0,1,2 层,直接返回n
  if (n === 0 || n === 1 || n === 2) {
    return n;
  }
  return climbStairs(n - 1) + climbStairs(n - 2);
}

// 爬楼梯方法  ----  循环方法
function climbStairs2 (n) {
  if (n === 0 || n === 1 || n === 2) {
    return n
  }
  let a = 1; // 当前层的前两层
  let b = 2; // 当前层的前一层
  let result = 0;
  for(let i = 3;i <= n;i ++) {
    result = a + b;
    a = b;
    b = result;
  }
  return result;
}

参考:yancy__zw6161080123