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常用算法的更多相关文章

  1. 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 ...

  2. GIS常用算法

    目录 1.常用算法 1.1.计算两经纬度点之间的距离 1.2.根据已知线段以及到起点距离,求目标点坐标 1.3.已知点.线段,求垂足 1.4.线段上距离目标点最近的点 1.5.点缓冲 1.6.点和面关 ...

  3. js常用工具类.

    一些js的工具类 复制代码 /** * Created by sevennight on 15-1-31. * js常用工具类 */ /** * 方法作用:[格式化时间] * 使用方法 * 示例: * ...

  4. 总结Objective-c常用算法

          今天是星期天,想睡到10点起床,结果认为自己太奢侈了,不能这么做,于是把闹钟设置成了6:30:结果终于9:36醒了,起床,无缘无故迟了,好吧,就算太累了吧,周天就原谅自己一回.终于到了中午 ...

  5. Atitit 编程语言常用算法attilax总结

    Atitit 编程语言常用算法attilax总结 1. 编译算法分类and   数据操作算法.1 1.1. Tab driver stat  状态转换表格算法1 1.2. Nest case 词法分析 ...

  6. GJM : 数据结构 - 轻松看懂机器学习十大常用算法 [转载]

     转载请联系原文作者 需要获得授权,非法转载 原文作者将享受侵权诉讼 文/不会停的蜗牛(简书作者)原文链接:http://www.jianshu.com/p/55a67c12d3e9 通过本篇文章可以 ...

  7. ACM常用算法及练习(2)

    ACM常用算法及练习 知识类型 重要度 容易度 应掌握度 典型题 其他           数据结构(5) 链表 ★★☆ ★★★ ★★☆     栈 stack ★★★ ★★★ ★★★ HLoj120 ...

  8. ACM常用算法及练习(1)

    ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...

  9. C/C++常用算法【C语言顺序查找(随机数)】【1】

    这是我学习唐峻,李淳的<C/C++常用算法第一天> 1.8.1. 查找数字: 程序随机生成一个拥有20个整数数据的数组,然后输入要查找的数据.接着,可以采用醉简单的逐个对比的方法进行查找, ...

随机推荐

  1. C++11 中的initialize_list

    这就是一个简单的模板类,不过在C++中有了特殊的语法支持,定义的时候使用如下的格式: initialize_list<double> dl = {1.1, 1.2}; 或者: initia ...

  2. Windows工作区目录创建

    Windows工作区目录创建批处理脚本,目的是养成工作区目录规范的好习惯. @echo off echo 'Create Jingyu Workshop!' rem Author: Alfred Zh ...

  3. C#转义字符(好记性不如烂笔头)

    C#转义字符: ·一种特殊的字符常量:·以反斜线"\"开头,后跟一个或几个字符.·具有特定的含义,不同于字符原有的意义,故称“转义”字符.·主要用来表示那些用一般字符不便于表示的控 ...

  4. redis 系列文章推荐

    推荐博客: Redis在linux上的安装: http://www.open-open.com/lib/view/open1426468117367.html Redis的三种启动方式: http:/ ...

  5. 【Head First Servlets and JSP】笔记 25:JSTL 参考

    <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ t ...

  6. 自动回复之实现随机回复与常用Mapper XML标签

    [常用Mapper XML标签] 1.基本的:select.insert.update 等 2.可读性.方便拼SQL:where.set.trim 3.减少重复:sql 4.逻辑控制:if.choos ...

  7. Django内置Admin解析

    Django 内置的admin是对于model中对应的数据表进行增删改查提供的组建 一.Django admin的内部依赖: 依赖的app django.contrib.auth django.con ...

  8. 小技巧|使用Vue.js的Mixins复用你的代码

    Vue中的混入 mixins 是一种提供分发 Vue 组件中可复用功能的非常灵活的方式.听说在3.0版本中可能会用Hooks的形式实现,但这并不妨碍它的强大. 这里主要来讨论 mixins 如何优化我 ...

  9. 基于Bootstrap的jQuery登录表单

    在线演示 本地下载

  10. Java套接字socket编程笔记

    相对于C和C++来说,Java中的socket编程是比较简单的,比较多的细节都已经被封装好了,每次创建socket连接只需要知道地址和端口即可. 在了解socket编程之前,我们先来了解一下读写数据的 ...