简单学习常见算法

1 字符串逆序输出算法

1.1 使用 reverse() 函数

首先将字符串转换为字符数组,然后通过调用原生的 reverse() 函数进行逆序,得到逆序数组后再通过 join() 函数得到逆序字符串。

function reverseStr(str) {
  return str
    .split("")
    .reverse()
    .join("");
}

let str = "abcdefg";
console.log(reverseStr(str));

1.2 使用栈的先进后出原则

栈是一种先进后出的原则,虽然 JS 并没有提供栈的结构,但是可以使用数组来模拟一个栈的结构。

function Stack() {
  this.data = [];
  this.top = 0;
}

Stack.prototype = {
  // 入栈:往栈中加入元素
  push: function(el) {
    this.data[this.top++] = el;
  },
  // 出栈:按后进先出原则返回元素
  pop: function() {
    return this.data[--this.top];
  },
};

function reverseStr(str) {
  let stack = new Stack();
  let strArr = str.split("");
  let result = "";

  // 把元素逐个放入到栈中
  for (let i = 0, l = strArr.length; i < l; i++) {
    stack.push(strArr[i]);
  }

  // 把栈中的元素逐个拿出来
  for (let i = 0, l = strArr.length; i < l; i++) {
    result += stack.pop();
  }

  return result;
}

let str = "abcdefg";
console.log(reverseStr(str));

1.3 使用递归逆序字符串

参考递归算法第三点


2 递归算法

递归就是一个函数直接或间接调用自身的一种方法。

1. 假设递归函数已经写好
2. 寻找递推关系
3. 将递推关系的结构转换为递归体
4. 将临界条件加入到递归体中

2.1 简单的递归练习

1️⃣ 求 n ~ m 的和。

// 1. 假设递归函数已经写好:_sum(n, m)
// 2. 寻找递推关系:m + _sum(n, m - 1)
// 3. 将临界条件加入到递归体中:m === n return n

function _sum(n, m) {
  if (m === n) return n;
  return m + _sum(n, m - 1);
}

console.log(_sum(10, 12));

2️⃣ 求 n~m 中奇数的和。

function _oddSum(n, m) {
  if (m % 2 === 0) m--;
  if (m === n) return n;
  if (m < n) return 0;
  return m + _oddSum(n, m - 2);
}

console.log(_oddSum(1, 7));

3️⃣ 求 n~m 中偶数的和。

function _evenSum(n, m) {
  if (m % 2 !== 0) m--;
  if (m === n) return n;
  if (m < n) return 0;
  return m + _oddSum(n, m - 2);
}

console.log(_evenSum(6, 8));

4️⃣ 斐波那契数列

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89... 求第 n 项
function fn(n) {
  if (n === 0 || n === 1) return 1;
  return fn(n - 1) + fn(n - 2)
}

console.log(fn(10));

2.2 高级递归练习

1️⃣ 阶乘

概念:阶乘是一个运算,一个数字的阶乘表示的是从 1 开始累乘到这个数字。比如:
3! = 1 * 2 * 3,规定 0! = 1

function fn(n) {
  if (n === 1 || n === 0) return 1;
  return n * fn(n - 1)
}

console.log(fn(5));

2️⃣ 求幂

function fn(n, m) {
  if (m === 0) return 1;
  if (m === 1) return n;
  return n * fn(n, m - 1);
}

console.log(fn(2, 5));

2.3 使用递归实现字符串逆序

function reverse(str, index, result = "") {
  if (index - 1 < 0) return result;
  result += str.charAt(--index);
  return reverse(str, index, result);
}

let str = "abcdefg";

console.log(reverse(str, str.length));

3 统计字符串中出现最多的字符及出现的次数

1️⃣ 算法一

主要思想是通过 key-value 形式的对象来存储字符串以及字符串出现的次数,然后逐个判断出现次数最大值,同时获取对应的字符。

function fn(str) {
  // 用来保存出现最多的字符和对应的次数
  let letter = "",
    maxCount = 0,
    strArr = [],
    strObj = {};

  strArr = str.split("");

  // 统计各个字符出现的次数
  strArr.forEach((item) => {
    if (strObj.hasOwnProperty(item)) {
      // 已经存在该字符,则对应的次数加 1
      strObj[item]++;
    } else {
      strObj[item] = 1;
    }
  });

  // 对比各个字符次数的大小
  for (item in strObj) {
    if (strObj[item] > maxCount) {
      letter = item;
      maxCount = strObj[item];
    }
  }

  return `{${letter}${maxCount}}`;
}

let str = "hellohtmlhellocsshellojshellovue";
console.log(fn(str));

2️⃣ 算法二

算法2的主要思想是对字符串进行排序,然后通过 lastIndexOf() 函数获取索引值后,判断索引值的大小以获取出现的最大次数。

  1. 首先调用 split() 函数将字符串转换数组,接着调用 sort() 函数进行排序,然后再调用 join() 函数转换成字符串。
  2. 遍历每个字符,通过调用 lastIndexOf() 函数,确定每个字符出现的最后位置,然后减去当前遍历的索引,就可以确定该字符出现的次数。
  3. 确定字符出现的次数后,直接与次数最大值 maxCount 进行比较,如果比 maxCount 大,则更新 maxCountmaxCountChar 的值。
  4. 计算完成后,将索引值设置为字符串出现的最后位置,进行下一轮计算,直到处理完所有字符。
function getMaxCount(str) {
  let maxCount = 0,
    maxCountChar = '';

  str = str.split('').sort().join('');

  for (let i = 0, l = str.length; i < l; i++) {
    let lastIndex = str.lastIndexOf(str[i]);
    let number = lastIndex - i + 1;

    if (number > maxCount) {
      maxCount = number;
      maxCountChar = str[i]
    }

    i = lastIndex;
  }

  return { maxCount, maxCountChar }
}

console.log(getMaxCount('hellohtmlhellowordhellovue'))

4 字符串去重

1️⃣ 算法一

算法一的主要思想是使用 key-value 类型的对象存储,key 表示唯一的字符,处理完成后将所有 key 拼接在一起即可得到去重后的效果。

  1. 首先通过 key-value 形式的对象来存储数据,key 表示不重复出现的字符,valueboolean 类型的值,为 true 则表示字符出现过。
  2. 然后遍历字符串,判断当前处理的字符是否在对象中,如果在,则不处理,如果不在,则将该字符添加到结果数组中。
  3. 处理完字符后,得到一个数组,转换为字符串后即可获得最终需要的结果。
function fn(str) {
  let strObj = {},
    result = [];

  for (let i = 0, l = str.length; i < l; i++) {
    if (!strObj.hasOwnProperty(str[i])) {
      strObj[str[i]] = true;
      result.push(str[i]);
    }
  }

  return result.join('')
}

console.log(fn('aaabbcdeffg'))

2️⃣ 算法二

算法二的主要思想是借助数组的 filter() 函数,在 filter() 函数中使用 indexOf() 函数判断。

  1. 通过 call 函数改变 filter() 函数的执行体,让字符串可以直接执行 filter() 函数。
  2. 在自定义的 filter() 函数回调中,通过 indexOf 函数判断其第一次出现的索引位置,如果与 filter() 函数中的 index 一样,则表示第一次出现,符合条件则 return 出去。这就表示只有第一次出现的字符会被成功过滤出来,而其他重复出现的字符会被忽略掉。
  3. filter() 函数返回的结果变身已经去重的字符数组,将其转换为字符串即可。
function fn(str) {
  let result = [];

  result = [].filter.call(str, (item, index) => {
    return str.indexOf(item) === index
  })

  return result.join('')
}

console.log(fn('aaabbcdeffg'))

5 求数组的最小值和最大值

5.1 通过prototype属性扩展min()和max()

1️⃣ 最小值:

/**
 * 方法一
 */
Array.prototype.min = function () {
  let minNumber = this[0],
    _length = this.length;

  for (let i = 0; i < _length; i++) {
    if (this[i] < minNumber) {
      minNumber = this[i];
    }
  }

  return minNumber;
}

/**
 *  方法二
 */
Array.prototype._min = function () {
  let arr = this.sort((a, b) => {
    if (a < b) {
      return -1;
    }
    if (a > b) {
      return 1;
    }
    return 0;
  });

  return arr[0];
}

let arr = [20, 3, 50, 7, 4, 1];
console.log(arr.min());
console.log(arr._min());

2️⃣ 最大值:

/**
 * 方法一
 */
Array.prototype.max = function () {
  let maxNumber = this[0],
    _length = this.length;

  for (let i = 0; i < _length; i++) {
    if (this[i] > maxNumber) {
      maxNumber = this[i];
    }
  }

  return maxNumber;
}

/**
 *  方法二
 */
Array.prototype._max = function () {
  let arr = this.sort((a, b) => {
    if (a < b) {
      return 1;
    }
    if (a > b) {
      return -1;
    }
    return 0;
  });

  return arr[0];
}

let arr = [20, 3, 50, 7, 4, 1];
console.log(arr.max());
console.log(arr._max());

5.2 借助Math的min()和max()

算法2的主要思想是通过apply()函数改变函数的执行体,将数组作为参数传递给apply()函数,这样数组就可以直接调用Math对象的min()函数和max()函数来获取返回值。

// ES5
Array.prototype.min = function () {
  return Math.min.apply(Math, this);
}

// ES5
Array.prototype.max = function () {
  return Math.max.apply(Math, this);
}

// ES6
Array.prototype._min = function () {
  return Math.min(...this);
}

// ES6
Array.prototype._max = function () {
  return Math.max(...this);
}

let arr = [6, 8, 3, 60, 40, 10];
console.log(arr.min());
console.log(arr.max());

参考资料

点击跳转

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值