十大算法(js实现)

二分查找

  • 需先进行排序再进行查找,非递归形式
  • 代码实现
			var arr = [1,2,3,4,5,6,7,8];
			function binarySearch(arr,target){
				var left = 0;
				var right = arr.length-1;
				while(left<=right){
					let mid = parseInt((left+right)/2);
					if(arr[mid]==target){
						return mid;
					}else if(arr[mid]>target){
						right = mid - 1;
					}else{
						left = mid + 1;
					}
				}
				return -1;
			}
			console.log(binarySearch(arr,9))

分治算法

  • 把复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题,直到最后的小问题可以简单地直接求解,原问题的解即子问题的解的合并
  • 常见的由分治算法解决的问题:二分搜索、大整数乘法、棋盘覆盖、合并排序、快速排序、线性时间选择、最接近点对问题、循环日程表、汉诺塔
  • 汉诺塔问题
    • 实现思路
      • n个盘的情况,将(n-1)个盘子移动到B
      • 把最下边的盘子移动到C
      • 把B的盘子移动到C
    • 代码实现
			function hanoiTower(num,a,b,c){
				if(num==1){
					document.write("第1个盘子从"+a+" => "+c +"<br />");
				}else{
					hanoiTower(num-1,a,c,b);
					document.write("第"+num+"个盘子从"+a+" => "+c +"<br />");
					hanoiTower(num-1,b,a,c);
				}
			}
			hanoiTower(3,"a","b","c")

动态规划

  • 将问题划分小问题进行解决从而一步步优化获取最优解的处理方法
  • 与分治算法不同的是动态规划适用于动态求解的问题,经分解得到的子问题往往不是相互独立的(即下一个子阶段的基础上进一步求解)
  • 背包问题
    • 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。
    • 主要思想
      • 每次遍历得到的第i个物品根据w[i]和v[i]来确定是否需要将该物品放入背包,即对于给定n个商品设v[i]w[i]分别为第i个物品的价格和重量,bag为背包重量,再令vAll[i][j]表示前i个物品中能够装入重量为i的背包中最大价值
      • vAll[i][0]=vAll[0][j]=0
      • 当w[i]>j时,vAll[i][j]=vAll[i-1][j](若准备加入的新增商品的容量大于当前背包的容量时,就直接使用上一单元格的值)
      • 当j>=w[i]时,vAll[i][j]=max(vAll[i-1][j],v[i]+vAll[i-1][j-w[i]])
    • 代码实现
			var w = new Array(4);
			w[1]=1;w[2]=4;w[3]=3;
			var v = new Array(4);
			v[1]=1500;v[2]=3000;v[3]=2000;
			function solve01Bag(w,v,bag){//bag表示背包的重量
				var vAll = new Array(w.length);
				//第一行和第一列均为0
				for(let i=0;i<vAll.length;i++){
					vAll[i]= new Array(bag+1);
					vAll[i][0] = 0;
				}
				for(let i=0;i<bag+1;i++){
					vAll[0][i] = 0;
				}
				// console.log(vAll)
				//遍历各个物品和背包容量
				for(let i=1;i<vAll.length;i++){
					for(let j=1;j<=bag;j++){
						if(w[i]>j){
							vAll[i][j]=vAll[i-1][j];
						}else{
							vAll[i][j]=Math.max(vAll[i-1][j],v[i]+vAll[i-1][j-w[i]]);
						}
					}
				}
				var max = vAll[vAll.length-1][bag]
				document.write("最大价值为"+max);
				return max;
			}
			solve01Bag(w,v,4)

KMP算法

  • 字符串查找算法,在一个文本中查找一个模式串第一次出现的位置
  • KMP方法利用之前判断信息,通过一个next数组保存模式串中前后最长公共子序列的长度,每次回溯时通过next数组找到前面模式匹配的位置省去了大量的计算时间
  • 部分匹配值,前缀后缀的最长公共共有元素长度
  • 算法思想
    • 先得到模式串的部分匹配表
    • 使用方法匹配表完成KMP匹配
  • 代码实现
			var str1 = "AABCSDJLKBXBDJSBCJK";
			var str2 = "AJLKBX";
			function kmpNext(str){
				var next = new Array(str.length);
				next[0]=0;
				for(let i=1,j=0;i<str.length;i++){
					while(j>0&&str[i]!=str[j]){
						j=next[j-1];
					}
					if(str[i]==str[j]){
						j++;
					}
					next[i]=j;
				}
				console.log(next)
				return next;
			}
			function kmpMatch(str1,str2,next){
				for(let i=0,j=0;i<str1.length;i++){
					while(j>0&&str1[i]!=str2[j]){
						j=next[j-1];
					}
					if(str1[i]==str2[j]){
						j++;
					}
					if(j==str2.length){
						return i-j+1;
					}
				}
				return -1;
			}
			var next = kmpNext(str2);
			var result = kmpMatch(str1,str2,next);
			console.log(result)

贪心算法

  • 对问题求解时,在每一步选择中都选择最好或者最优(即最有利的)的选择,从而希望能够导致结果是最好的或者最优

  • 所得结果不一定是最优的但都是相对接近最优解的结果

  • 集合覆盖问题

    • 图解
      在这里插入图片描述
  • 代码实现

			var broadcast = new Map();
			
			var set1 = new Set();
			set1.add("北京");
			set1.add("上海");
			set1.add("天津");
			
			var set2 = new Set();
			set2.add("广州");
			set2.add("北京");
			set2.add("深圳");
			
			var set3 = new Set();
			set3.add("成都");
			set3.add("上海");
			set3.add("杭州");
			
			var set4 = new Set();
			set4.add("上海");
			set4.add("天津");
			
			var set5 = new Set();
			set5.add("杭州");
			set5.add("大连");
			
			broadcast.set("K1",set1);
			broadcast.set("K2",set2);
			broadcast.set("K3",set3);
			broadcast.set("K4",set4);
			broadcast.set("K5",set5);
			// console.log(broadcast)
			
			var allAreas = new Set();
			broadcast.forEach((set)=>{
				set.forEach((area)=>{
					allAreas.add(area);
				})
			})
			
			var selects = new Array();
			var maxKey = null;
			var temp = new Set();//存放key所遍历的广播覆盖的城市和allAreas的交集
			
			while(allAreas.size){
				broadcast.forEach((set,key)=>{
					temp.clear();
					maxKey=null;
					set.forEach((area)=>{
						temp.add(area);
					})
					let intersect = new Set([...allAreas].filter(x => temp.has(x)));
					console.log(intersect);
					
					//当前maxkey指向的广播站为空或者key指向的数量没有当前大
					if(intersect.size>0&&(maxKey==null||intersect.size>broadcast.get(maxKey).size)){
						maxKey=key;
					}
					if(maxKey!=null){
						selects.push(maxKey);
						broadcast.forEach((set,key)=>{
							if(key==maxKey){
								set.forEach((area)=>{
									allAreas.delete(area);
								})
							}
							
						})
					}
				})
			}
			console.log(selects)

最小生成树(MST)

  • 给定一个带权的无向连通图,如何选取一课生成树,使树上所有边的权总和最小
  • n个顶点一定有n-1条边,包含全部顶点,n-1条边都在图中

普利姆算法(prim)

  • 找到最小连通子图(n个顶点只有n-1条边)
  • 算法思想
    • 设G=(V ,E)是连通图,T=(U,I)是最小生成树,V,U 是顶点结合,E,D是边的集合
    • 若从顶点u开始构造最小生成树,则从集合v中取出顶点u放入集合中,标记顶点v的visited[u]=1;
    • 若集合U中顶点ui与集合VU中的顶点vj之间存在边则寻找这些边中权值最小的边,但不能构成回路,将顶点vj放入集合U中,将边(ui,vj)加入到集合中,标记visited[vj]=1;
    • 重复以上步骤直至找到n-1条边
  • 图示
    在这里插入图片描述
  • 代码实现
			class Gragh{
				constructor(n,arr) {
				    this.vertexList = arr ;
					this.edges = new Array(n);
					for(let i=0;i<n;i++){
						this.edges[i]= new Array(n);
						for(let j=0;j<n;j++){
							this.edges[i][j]=10000;
						}
					}
					this.edgesNum = 0;
				}
				insertEdge(v1,v2,weight){
					this.edges[v1][v2]=weight;
					this.edges[v2][v1]=weight;
					this.edgesNum++;
				}
				showGragh(){
					for(let i=0;i<this.vertexList.length;i++){
						for(let j=0;j<this.vertexList.length;j++){
							if(this.edges[i][j]!=undefined){
								document.write(this.edges[i][j]+" ");
							}else{
								document.write("0 ");
							}
						}
						document.write("<br />");
					}
				}
			}
			var gragh = new Gragh(7,['A','B','C','D','E','F','G']);
			gragh.insertEdge(0,1,5);
			gragh.insertEdge(0,6,2);
			gragh.insertEdge(0,2,7);
			
			gragh.insertEdge(1,6,3);
			gragh.insertEdge(1,3,9);
			
			gragh.insertEdge(2,4,8);
			
			gragh.insertEdge(3,5,4);
			
			gragh.insertEdge(4,5,5);
			gragh.insertEdge(4,6,4);
			
			gragh.insertEdge(5,6,6);
			// gragh.showGragh();

			function prim(gragh,v){//v表示从哪个节点开始
				var n = gragh.vertexList.length;
				var visited = new Array(n);
				for(let i=0;i<n;i++){
					visited[i]=0;
				}
				visited[v]=1;
				var h1=-1;//存放临时的最小边的两个节点
				var h2=-1;
				var minWeight = 10000;
				for(let k=1;k<n;k++){
					for(let i=0;i<n;i++){//访问过的节点
						for(let j=0;j<n;j++){//未访问过的节点
							if(visited[i]==1&&visited[j]==0&&gragh.edges[i][j]<minWeight){
								minWeight=gragh.edges[i][j];
								h1=i;h2=j;
							}
						}
					}
					document.write("边<"+gragh.vertexList[h1]+"-"+gragh.vertexList[h2]+">的权值为"+minWeight+"<br />");
					visited[h2]=1;
					minWeight=10000;
				}
			}

			prim(gragh,0)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值