js常用算法
1.判断一个字符串是“回文”类型,回文:形如‘abcba’、‘mamam’这种第一个与最后一个字符相同,第二个和倒数第二个字符相同。。。一次类推,该怎么实现呢?
对与我来说,首先看到第一眼,还真没想起来怎么处理,后来想到用reverse()就可以啊!MD!那是数组的方法!!!总之要用reverse()方法,那就先转成数组,再转成字符串来比较就行了啊
function checkReverseString(str) {
return str == str.split('').reverse().join('');
}
2.数组去重:
先来看用老方法处理:
1).object对象中是否存在当前key
var arr = [1,2,3,1,2,3]
function uniqueArr(arr) {
var obj = {}
var result = []
for (var i = 0, len = arr.length; i < len; i++) {
if (!obj[arr[i]]) {
obj[arr[i]] = true
result.push(arr[i])
}
}
return result
}
2) Array.indexOf()
var arr = [1,2,3,1,2,3]
function uniqueArr(arr) {
var obj = arr
var result = []
for (var i = 0, len = arr.length; i < len; i++) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i])
}
}
return result
}
3) ES5 filter
[1,1,2,2,3,'a','a'].filter(function(ele,index,array){
return index === array.indexOf(ele)
})
indexOf(ele)检查到的是第一次遇到当前项的下标,我们看到数字1,出现了两次次,0位置和1位置,indexOf(1) 永远都等于0,所以1位置的1就不符合filter传入的规则,只返回0位置的1.
4)ES5 reduce(fn(), el, index, array)
[1,1,2,3].reduce((result, el, i, arr) => {
if (i === arr.indexOf(el)) {
result.push(el)
} return result
}, [])
也是循环每一项,每一项的处理都在内部函数中处理。
5) ES6 Array.from(new Set()),set中不存在重复的项:
var arr = [1,2,3,1,2,3]
var arr1 = Array.from(new Set(arr))
console.log(arr1)
还是这种方法好啊,清清爽爽!
3.统计一个字符串中出现次数最多的字符和出现的次数
刚开始没有太多的思路,刚才数组去重,用到了obj key的属性,那这里是不是也可以用呢?遇到新的字符,obj的该字符的值设为1,再遇到就+1,来试试:
var str = 'aaaabbbc'
function maxSym(str) {
if (str && str.length <= 1) {
return str
}
var obj = {}
for (var i = 0, len = str.length; i < len; i++) {
obj[str[i]] = obj[str[i]] ? obj[str[i]] + 1 : 1
// 这里只能写obj[str[i]] + 1,其他写法,例如++,执行会有问题,如果你知道为什么请告诉我
}
var maxStr = ''
var maxCount = 0
for (var key in obj) {
if (obj[key] > maxCount) {
maxStr = key
maxCount = obj[key]
}
}
return maxStr + ':' + maxCount
}
console.log(maxSym(str))
4.不愿意看到的排序,还是要来的
1).先看看冒泡排序,必须要掌握
var arr = [2,34,4,1]
function bubbleSort(arr) {
if (arr && arr.length <= 1) {
return arr
}
for (var i = 0, len = arr.length; i < len - 1; i ++) { // 控制循环的轮数,为什么要len - 1?要比较有两个元素的数组[2,1],请问比较几轮?1轮!以此类推:len-1
for (var j = 0; j < len - i - 1; j ++) { // 控制每轮要比较的次数
if (arr[j] > arr[j+1]) {
var temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
console.log(arr)
}
return arr
}
console.log(bubbleSort(arr))
2). 选择排序:
和冒泡排序原理差不多,但不是两两比较,立即换位置,而是执行完一轮,再互换位置:
[3,4,5,1,7],假设第0位3是最小的数,与后一位比较3 < 4,再往后 3 < 5, 再往后 3 > 1, 到这里,最小的数的位置应该变成第3位,把这个位置记下来,然后继续往后比较 1 < 7,到这里就比较结束了,现在需要互换位置了,现在最小的数的位置在第3位,应该转换成[1,4,5,3,7],也就是“假定最小的”和真实最小的互换位置。第0位已经是最小的数了。第二轮,从第1位开始算起,以此类推,完成排序
function selectionSort(arr) {
var len = arr.length, min;
for (var i = 0; i < len; i ++) {
min = i // 假定第i轮循环的第一个数最小,把这个位置保存起来
for (var j = i + 1; j < len; j ++) {
if (arr[j] < arr[min]) {
min = j // 如果后面有更小的数,把这个位置记为最小
}
}
if (i != min) { // 如果后面有更小的数,第i轮第一个数要和更小的数互换位置
var temp = arr[min]
arr[min] = arr[i]
arr[i] = temp
}
}
return arr
}
var arr = [3,4,5,1,7]
console.log(selectionSort(arr))
过程:
[3,4,5,1,7] => [1,4,5,3,7] => [1,3,5,4,7] => [1,3,4,5,7] => [1,3,4,5,7]
3).插值排序:(斗地主的时候,左手里面的牌,是不是排好序的?右手随意起牌,差到左手里已经排好序的牌中,这个过程就是插值排序)
function inputSort(data) {
var temp;
for (var i = 1; i < data.length; i++) {
for(var j = i; (j > 0) && (data[j] < data[j - 1]); j--) {
temp = data[j];
data[j] = data[j - 1]
data[j - 1] = temp
}
}
return data
}
var arr = [4,3,2,5,1]
console.log(inputSort(arr))
4)合并排序,MD,老菜鸟,写不动了,先到这里,让我好好理解一下
归并排序,采用了‘分’,分而治之,然后再合。
// 先看把两个有序数组合并
function merge(left, right) {
var result = []
while (left.length > 0 && right.length > 0) {
if (left[0] < right[0]) { // 左边数组的第一个数值,小于右边数组第一个数值
result.push(left.shift()) // 把左边数组第一个数值取出来,并添加到result中
} else {
result.push(right.shift()) // 否则把右边数组第一个数值取出来,并添加到result中
}
}
// 比如 left = [1, 2] right = [3, 4] ,
// 只发生两次比较,第一次: 1 < 3 , result = [1]
// 第二次: 2 < 3 , result = [1, 2]
// 这个时候left已经空了,length => 0 , 所以while 循环结束,但是right = [3, 4]
// 当然也可能是right先变成[],
// 所以要把result、left和right拼接在一起返回,得到最终结果
return result.concat(left, right)
} // 这里的主要功能是拆分数组,至少拆成两个数组,才能使用merge方法,所以使用递归,一直拆下去,
// 当数组的长度小于等于1的时候,终止递归拆分,执行merge操作,并返回merge后的结果
// 递归调用的逻辑,可能会比较绕,多理解一下,还是没大问题的!加油!
function mergeSort(arr) {
if (arr.length <= 1) {
return arr
}
var middle = Math.floor(arr.length / 2) // 取中间序列号
var left = arr.slice(0, middle) // 取中间序列号之前的部分,赋值给left
var right = arr.slice(middle) // 取中间序列号之后的部分,赋值给right
return merge(mergeSort(left), mergeSort(right)) // 执行merge操作,其实这里面是先把大数组递归拆成单元素数组,再merge
} var arr = [3,1,4,2,6]
console.log(mergeSort(arr))
结果:
5).快速排序,先找到一个中间值,然后遍历,把比中间值小的放在左边数组,把比中间值大的放在右边数组,然后再分别按这种思路对两个新数组比较,以此类推,直到结束。
var arr = [2,34,3,4]
function quickSort(arr) {
if (arr && arr.length <= 1) {
return arr
}
var midEl = arr[0] //
var left = []
var right = []
for (var i = 1, len = arr.length; i < len; i++) {
if (arr[i] < midEl) {
left.push(arr[i]) // 比第一个数小的数放在左边
} else {
right.push(arr[i])
}
}
return quickSort(left).concat([midEl], quickSort(right))
}
console.log(quickSort(arr))
这种方式会额外增加两个数组,空间复杂度高,下面说一个更节省空间的写法,必须掌握。
function quickSort(arr) {
if (arr.length <= 1) { // 数组长度为1时,默认数组有序
return arr
} let flag = arr[0] // 取第0个元素为 中间值(当然你可以随便取,比如取最后一个)
let i = 1 // 令左边指针初始化为1
let j = arr.length - 1 // 令右边指针初始化为 数组长度-1 while(i < j) { // 如果左指针还小于又指针,则继续判断
while(arr[j] >= flag && i < j) { // 如果 右边 的数大于 flag , 不做操作,继续左移,因为大数本来就该在右边
j--
}
while(arr[i] <= flag && i < j) { // 如果 左边 的数小于 flag, 不做操作,继续右移,因为小数本来就该在左边
i++
}
let temp = arr[j] // 如果不满足上面两个条件,也就是说,左边出现了大数,且右边出现了小数,则执行交换
arr[j] = arr[i]
arr[i] = temp
}
let temp = arr[0] // 最后调换 中间值 与 右指针(也是左指针,因为此时左右指针索引相等),到此第一次遍排序结束
arr[0] = arr[j]
arr[j] = temp
return quickSort(arr.slice(0,i)).concat([flag]).concat(quickSort(arr.slice(j+1))) // 递归调用即可实现整体排序
}
var a = [13,1,3,45,2,56,6,10]
var b = quickSort(a)
console.log(b)
结果:
5、递归:求和问题、(待补充其他类型)
function fn(n) {
if (n === 1) return 1
return n + fn(n - 1)
}
function fn(n) {
return n && n + fn(n - 1)
}
fn(5) // 15
6、产生斐波那契数列,并用canvas画图,[0, 1, 1, 2, 3, 5, 8, 13, 21, 34...],数组中的每一项当做圆的半径,每次画1/4圆。
var canvas = document.getElementsByTagName('canvas')[0]
canvas.width = 600
canvas.height = 480
var ctx = canvas.getContext('2d')
var coor = {x: 300, y: 240}
function draw(r1, n, r2) { // r1-前一个圆的半径,n-数组下标,r2-下标圆的半径
var r = r2 * 5 // 半径太小,放大5倍
var startAngle = Math.PI // 起始角
var endAngle = Math.PI * 0.5 // 终止角
var antiClockWise = true // 逆时针方向
// 两内切圆满足的条件: 1、两圆的圆心距d,等于大圆的半径r2减去小圆的半径r1,即: d = r2 - r1.
// 依据上述条件,可以得出下一个圆的圆心坐标:注意,下一个圆的坐标值,有一个值和当前圆的一致,因为无论哪种情况,两圆心都会在一条直线上。
// 所以有一下结论: x2 = x1 +(-) d;y2 = y1 +(-) d => x2 = x1 +(-) (r2 - r1);y2 = y1 +(-) (r2 - r1)
if (n > 2) {
switch(n % 4) {
case 0: // n = 4、8、12...第一象限
coor.x = coor.x - (r - (r1 * 5)) // 这里刚开始会比较难理解,注意对照上面的推导关系,会好理解一些. *5 是因为r = r2 * 5,所以
// r1也放大5倍
startAngle = 0
endAngle = Math.PI * 1.5
break;
case 1: // n = 5、9、13...第二象限
coor.y = coor.y + (r - (r1 * 5))
startAngle = Math.PI * 1.5
endAngle = Math.PI
break;
case 2: // n = 6、10、14...第三象限
coor.x = coor.x + (r - (r1 * 5))
startAngle = Math.PI
endAngle = Math.PI * 0.5
break;
case 3: // n = 3、7、11...第四象限
coor.y = coor.y - (r - (r1 * 5))
startAngle = Math.PI * 0.5
endAngle = 0
break;
}
}
ctx.beginPath()
ctx.arc(coor.x, coor.y, r, startAngle, endAngle, antiClockWise)
ctx.lineWidth = 3
ctx.strokeStyle = "#f34e56"
ctx.stroke()
} function getFibonacci(n) {
var i = 0
var arr = []
while(i < n) {
if (i <= 1) {
arr.push(i)
} else {
arr.push(arr[i - 2] + arr[i - 1]) // arr[i] = arr[i - 2] + arr[i - 1]
}
i++
}
return arr
}
var arrFibonacci = getFibonacci(10)
console.log(arrFibonacci)
for (var j = 0; j < arrFibonacci.length; j++) {
if (j >= 2) { // 数组长度至少为3,才满足斐波那契数组定义
draw(arrFibonacci[j - 1], j, arrFibonacci[j])
}
}
结果如图:
7、合并两个有序数组:
var a = [2,4,6], b = [1,3]
function two(left = [], right = []) {
var result = []
while(left.length && right.length) {
result.push(left[0] <= right[0] ? left.shift() : right.shift())
}
return result.concat(left, right)
}
js常用算法的更多相关文章
- Atitit.跨语言 java c#.net php js常用的codec encode算法api 兼容性 应该内置到语言里面
Atitit.跨语言 java c#.net php js常用的codec encode算法api 兼容性 应该内置到语言里面 1. 常用算法1 1.1. 目录2 1.2. 定义和用法编辑2 1.3 ...
- GIS常用算法
目录 1.常用算法 1.1.计算两经纬度点之间的距离 1.2.根据已知线段以及到起点距离,求目标点坐标 1.3.已知点.线段,求垂足 1.4.线段上距离目标点最近的点 1.5.点缓冲 1.6.点和面关 ...
- js常用工具类.
一些js的工具类 复制代码 /** * Created by sevennight on 15-1-31. * js常用工具类 */ /** * 方法作用:[格式化时间] * 使用方法 * 示例: * ...
- 总结Objective-c常用算法
今天是星期天,想睡到10点起床,结果认为自己太奢侈了,不能这么做,于是把闹钟设置成了6:30:结果终于9:36醒了,起床,无缘无故迟了,好吧,就算太累了吧,周天就原谅自己一回.终于到了中午 ...
- Atitit 编程语言常用算法attilax总结
Atitit 编程语言常用算法attilax总结 1. 编译算法分类and 数据操作算法.1 1.1. Tab driver stat 状态转换表格算法1 1.2. Nest case 词法分析 ...
- GJM : 数据结构 - 轻松看懂机器学习十大常用算法 [转载]
转载请联系原文作者 需要获得授权,非法转载 原文作者将享受侵权诉讼 文/不会停的蜗牛(简书作者)原文链接:http://www.jianshu.com/p/55a67c12d3e9 通过本篇文章可以 ...
- ACM常用算法及练习(2)
ACM常用算法及练习 知识类型 重要度 容易度 应掌握度 典型题 其他 数据结构(5) 链表 ★★☆ ★★★ ★★☆ 栈 stack ★★★ ★★★ ★★★ HLoj120 ...
- ACM常用算法及练习(1)
ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...
- C/C++常用算法【C语言顺序查找(随机数)】【1】
这是我学习唐峻,李淳的<C/C++常用算法第一天> 1.8.1. 查找数字: 程序随机生成一个拥有20个整数数据的数组,然后输入要查找的数据.接着,可以采用醉简单的逐个对比的方法进行查找, ...
随机推荐
- C语言-随机数
C语言使用rand()函数产生随机数, 使用rand()函数之前要先使用srand(time(0)), 以当前时间作为种子, 否则产生的随机数将不会变化. #include <stdio.h&g ...
- 解释一下python中的赋值运算符
我们将所有的算术运算符和赋值运算符号放在一起展示 a=7 a+=1 print(a) a-=1 print(a) a*=2 print(a) a/=2 print(a) a**=2 print(a) ...
- Getting Started with Rails (1)
按照官网http://guides.rubyonrails.org/getting_started.html上学习了一下例子.在过程中有很多刚开始没理解的地方,写下来. 首先,建立了一个resourc ...
- 新建Maven项目时出错:org.apache.maven.archiver.MavenArchiver.getManifest
新建Maven项目时出错:org.apache.maven.archiver.MavenArchiver.getManifest eclipse新建maven项目时,pom.xml文件第一行报错: o ...
- 大数据生态,哪些框架需要全部启动,哪些只启动master,仅为汇总
主从,只需要在master节点启动 hadoop hbase 单机启动 hive 其他,需要启动每个节点 zookeeper kafka flume presto
- JavaScript消息机制入门篇
JavaScript这个语言本身就是建立在一种消息机制上的,所以它很容易处理异步回调和各种事件.这个概念与普通的编程语言基础是不同的,所以让很多刚接触JavaScript的人摸不着头脑.JavaScr ...
- 【JavaScript】键盘控制小球
参考: 1.Simple Canvas Game 2.javaScript 事件监听 <!DOCTYPE html> <html> <head> <meta ...
- Django学习笔记之使用 Django项目开发框架
Django 项目是一个定制框架,它源自一个在线新闻 Web 站点,于 2005 年以开源的形式被释放出来.Django 框架的核心组件有: 用于创建模型的对象关系映射 为最终用户设计的完美管理界面 ...
- 20145201 《Java程序设计》第一周学习总结(修改)
# 20145201 <Java程序设计>第一周学习总结 ## 教材学习内容总结 万事开头难,终于开始学习了Java.寒假的时候看到老师的要求确实有点慌,但是这周翻开书,从书本知识第一行学 ...
- 2062326 齐力锋 实验二《Java面向对象程序设计》实验报告
北京电子科技学院(BESTI) 实 验 报 告 课程: 程序设计与数据结构 班级: 1623 姓名: 齐力锋 学 ...