文章目录
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()
函数获取索引值后,判断索引值的大小以获取出现的最大次数。
- 首先调用
split()
函数将字符串转换数组,接着调用sort()
函数进行排序,然后再调用join()
函数转换成字符串。 - 遍历每个字符,通过调用
lastIndexOf()
函数,确定每个字符出现的最后位置,然后减去当前遍历的索引,就可以确定该字符出现的次数。 - 确定字符出现的次数后,直接与次数最大值
maxCount
进行比较,如果比maxCount
大,则更新maxCount
和maxCountChar
的值。 - 计算完成后,将索引值设置为字符串出现的最后位置,进行下一轮计算,直到处理完所有字符。
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
拼接在一起即可得到去重后的效果。
- 首先通过
key-value
形式的对象来存储数据,key
表示不重复出现的字符,value
为boolean
类型的值,为true
则表示字符出现过。 - 然后遍历字符串,判断当前处理的字符是否在对象中,如果在,则不处理,如果不在,则将该字符添加到结果数组中。
- 处理完字符后,得到一个数组,转换为字符串后即可获得最终需要的结果。
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()
函数判断。
- 通过
call
函数改变filter()
函数的执行体,让字符串可以直接执行filter()
函数。 - 在自定义的
filter()
函数回调中,通过indexOf
函数判断其第一次出现的索引位置,如果与filter()
函数中的index
一样,则表示第一次出现,符合条件则return
出去。这就表示只有第一次出现的字符会被成功过滤出来,而其他重复出现的字符会被忽略掉。 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());