文章目录
- 1,二分查找(非递归)
- 2,分治思想
- 3,动态规划
- 4,KMP算法(字符串查找算法)
- 5,贪心算法
- 6,普里姆算法(最小生成树)
- 7,克鲁斯卡尔算法(最小生成树)
- 8,迪杰斯特拉算法(最短路径)
- 9,弗洛伊德算法(最短路径)
- 10,马踏棋盘算法(骑士周游)
1,二分查找(非递归)
在有序数组中查找特定的值。
代码比较死。
升序的版本:
function search(arr, target) {
let left = 0
let right = arr.length - 1
while (left <= right) {
let middle = Math.floor((left + right) / 2)
if (arr[middle] === target) {
return middle
} else if (arr[middle] > target) {
right = middle - 1
} else {
left = middle + 1
}
}
return -1
}
console.log(search([1, 2, 3, 4, 5, 6, 7], 7))
2,分治思想
把复杂的问题拆解成多个子问题。
步骤为:
- 分解。
- 解决。
- 合并。
汉诺塔问题的解:
有三个位置:原位置,中间盘,目标盘。
- 将N个盘划分为N-1个盘和1个盘。
- N-1个盘递归地移动到中间盘。
- 1个盘直接移动到目标盘。
- N-1个盘递归地移动到目标盘。
//统计步数
let count = 0
//三个数组
let A = [5, 4, 3, 2, 1]
let B = []
let C = []
//打印状态
function printInfo() {
console.log("A:" + A)
console.log("B:" + B)
console.log("C:" + C)
console.log("=============================" + (++count))
}
//调用
han(A.length, A, C, B)
function han(n, from, to, middle) {
//最上面的一个,直接push,pop,打印状态
if (n === 1) {
to.push(from.pop())
printInfo()
//下面的N个,三步走
} else {
han(n - 1, from, middle, to)
han(1, from, to, middle)
han(n - 1, middle, to, from)
}
}
3,动态规划
排列组合,求最优解。
同样是拆分问题,它的子问题互相关联。后面依赖前面。
背包问题的解:
填表,种类逐渐增加,重量逐渐增加。
0磅:无法放东西。
0种物品:无东西可放。
只有吉他:都是吉他
吉他+音响:123是吉他,4是音响
吉他+音响+电脑:12是上一层的值,3是电脑,4是上一层的值与(当前+以前层)的较大者。
4,KMP算法(字符串查找算法)
在字符串A中匹配子串B。
暴力匹配:不匹配就回溯。
let a = "123456789344566777"
let b = "344566"
function search(source, target) {
let i = 0
let j = 0
//遍历
while (i < source.length) {
if (j > target.length - 1) {
return i - j + 1
}
if (source[i] !== target[j]) {
i = i - j + 1
j = 0
} else {
i++
j++
}
}
return -1
}
console.log(search(a, b))
KMP:
如果要匹配ABCD,回溯了,不需要从B位置处开始和A匹配。
而是从D后面直接开始。
如果要匹配ABCDAB,回溯了,那就从后面的A处开始匹配。
一种实现:
// 主串
let str1 = 'BBC ABCDAB ABCDABCDABDEDC';
// 模式串
let str2 = 'ABCDABD';
let getPMT = (str = '') => {
if (str.length === 0) return [];
let pmt = [0];
let k = 2;
while (k <= str.length) {
let temp = str.substring(0, k);
let length = temp.length;
// 前缀
let prefix = temp.substring(0, length - 1).split('').map((item, index) => {
return temp.substring(0, index + 1);
});
// 后缀
let suffix = temp.substring(1).split('').map((item, index) => {
return temp.substring(index + 1);
});
let publicLength = 0;
// 比较前缀后缀得出最长公共字符长度
prefix.forEach(preitem => {
suffix.forEach(sufitem => {
if (preitem === sufitem) {
publicLength = preitem.length > publicLength ? preitem.length : publicLength;
}
})
})
pmt.push(publicLength);
k++;
}
return pmt;
}
let pmt = getPMT(str2);
let m = 0;
let n = 0;
while (m < str1.length && n < str2.length) {
if (str1[m] === str2[n]) { // 匹配时,继续比较下一个字符
n++;
m++;
} else if (n > 0) { // 当前不匹配时,如果前面已匹配字符数 > 0,模式串索引往前移动pmt[n - 1]位
n = pmt[n - 1];
} else {
m++;
}
}
if (n === str2.length) {
console.log(`str1包含str2,索引位置为${m - str2.length}至${m - 1}`);
} else {
console.log('str1不包含str2');
}
5,贪心算法
排列组合,求最优解。
每次都选一个最优解,直到解决问题。
先挑选覆盖数量多的,K1,
重新计算覆盖数量。取最大的,K2。
K3。
k5。
此时已经全覆盖了,不再挑选。
6,普里姆算法(最小生成树)
最优解(待补充)
7,克鲁斯卡尔算法(最小生成树)
最优解(待补充)
8,迪杰斯特拉算法(最短路径)
最优解(待补充)
9,弗洛伊德算法(最短路径)
最优解(待补充)
10,马踏棋盘算法(骑士周游)
全经历(待补充)