# js算法思想学习

  • 算法的本质是寻找规律并实现
  • 如何找到规律?发现输入和输出的关系,找到突破点
  • 复杂的实现怎么办? 实现是程序加数据结构的结合体
  • 数据结构用来保存数据和调度,本身一个代码的实现靠的是程序结构和数据结构的配合

# 基础算法(5)

# 字符串

# 反转字符串中的单词

// reverse()方法是数组方法,故需要先将item.split('')由字符串变为数组
  export function reverseWord(str){
    return str.split(' ').map(item => {
      return item.split('').reverse().join('')
    }).join(' ')
  }
  // split分割 匹配正则,\s空格, g全局匹配,查找所有匹配,而非在找到第一个匹配后停止
  export function reverseWord1(str){
    return str.split(/\s/g).map(item => {
      return item.split('').reverse().join('')
    }).join(' ')
  }

  // match识别 匹配正则,[]可选项,\w匹配大写字母小写字母0-9_,+多余1次, g全局匹配,查找所有匹配,而非在找到第一个匹配后停止
  export function reverseWord2(str){
    return str.match(/[\w']+/g).map(item => {
      return item.split('').reverse().join('')
    }).join(' ')
  }

# 计算二进制字串

function a(s) {
      let r = [];
      let match = (str) => {
        let j = str.match(/^(0+|1+)/)[0]
        let o = (j[0] ^ 1).toString().repeat(j.length)
        let reg = new RegExp(`^(${j}${o})`)
        if (reg.test(str)) {
          return RegExp.$1
        } else {
          return ''
        }
      }
      for (let i = 0; i < s.length - 1; i++) {
        let sub = match(s.slice(i))
        if (sub) {
          r.push(sub)
        }
      }
      console.log(r)
    };

# 数组

# 电话号码的组合(公式运算)

# 卡牌分组(归类运算)

# 种花问题(筛选运算)

# 格雷编码(编码运算)

# 正则表达式

# 重复的子字符串

# 正则表达式匹配

# 排序 *****

  • 时间复杂度: 看得是运行次数, 空间复杂度: 看得是占用内存情况
  • 参考连接:https://www.jianshu.com/p/f4cca5ce055a

# 快速排序

# 冒泡排序

// 原理: 相邻两两比较,然后换位置
function bubbleSort(arr){
  for(let i=arr.length-1, temp; i>0; i--){ //定义每次循环的遍历次数,即边界
    for(let j=0; j<i; j++){ //定义从当前位置遍历到哪个边界
      if(arr[j]>arr[j+1]){ //比较大小
        temp=arr[j] //暂存当前元素
        arr[j]=arr[j+1] //交换位置,冒泡输出元素
        arr[j+1]=temp
      }
    }
  }
  return arr
}

# 选择排序

// 原理:从当前元素开始,选择比ta小的元素,跟ta交换位置
function selectionSort(arr){
  for(var i=0, len=arr.length, min; i<len;i++){ //确定每次循环的循环边界
    min=arr[i] //暂存当前元素
    for(var j=i+1;j<len;j++){ //从循环边界开始遍历到最后,找出比当前元素小的元素
      if(arr[j]<min){ 
        var c = min
        min=arr[j]
        arr[j]=c
      }
    }
    arr[i]=min //将找出的最小值赋值给当前元素
  }
  return arr
}

  export function selectSort(arr){
    for(let i = 0, len = arr.length,tmp; i< len; i++){
      for(let j = i+1; j < len; j++){
        if(arr[i]<arr[j]){
          tmp = arr[i]
          arr[i] = arr[j]
          arr[j] = tmp
        }
      }
    }
    return arr
  }

# 希尔排序

# 按奇偶排序数组

export function oddSort(arr){
    // 进行升序排序
    arr.sort((a,b)=>a-b)
    // 声明一个空数组来存储奇偶排序后的数组
    let r=[]
    // 记录奇数和偶数位下标
    let odd=1
    let even=0
    arr.forEach(item=>{
      if(item%2===1){
        r[odd]=item
        odd+=2
      }else{
        r[even]=item
        even+=2
      }
    })
    return r
  }

# 数组中的第k个最大元素

  • 思路:1)排序 2)遍历
  // 代码量少,但性能较差,需要循环遍历整个数组
  export function sort(arr, k){
    return arr.sort((a, b)=>b-a)[k-1]
  }
  // 性能较好,借助冒泡原理,只需遍历k次,降序排
  export function sort1(arr, k){
    let len = arr.lenth-1
    for(let i = len, tmp; i > len-k; i--){
      for(let j = 0; j < i; j++){
        if(arr[j]<arr[j+1]){
          tmp = arr[j]
          arr[j] = arr[j+1]
          arr[j+1] = tmp
        }
      }
    }
    return arr[k-1]
  }
  // 性能较好,借助冒泡原理,只需遍历k次,升序排
  export function sort2(arr, k){
    let len = arr.length-1
    for(let i = len, tmp; i < len-k; i--){
      for(let j = 0; j < i; j++){
        if(arr[j]>arr[j+1]){
          tmp = arr[j]
          arr[j] = arr[j+1]
          arr[j+1] = tmp
        }
      }
    }
    // return arr[len-k+1]
    return arr[len-(k-1)]
  }

# 最大间距

// 法一:常规解法,性能不高,sort()方法遍历一次,寻找差值时又遍历一次
function maxSpace(arr){
  // 如果数组长度小于2返回0
  if(arr.length<2){
    return 0
  }
  // 排序
  arr.sort()
  // 暂存相邻元素的最大差值
  var max = 0
  for(var i=0, len=arr.lenth-1, tmp; i<len; i++){ //当前元素与下一元素比较
    tmp = arr[i+1]-arr[i]  //tmp暂存相邻两元素间差值
    if(tmp>max){
      max=tmp
    }
  }
  return max
}
// 法二:
function maxinumGap(arr){
  if(arr.length<2){
    return 0
  }
  let max = 0
  let len = arr.lenth-1
  let space
  for(let i=len, tmp; i>0; i--){
    for(let j=0; j<i; j++){
      tmp = arr[j]
      if(tmp<arr[j+1]){
        arr[j] = arr[j+1]
        arr[j+1] = tmp
      }
    }
    if(i<len){
      space= arr[i+1]-arr[i]
      if(space>max){
        max = space
      }
    }
  }
  return Math.max(max, arr[1]-arr[0])
}

# 缺失的第一个正数

// 法一: sort()排序一次,for循环一次,性能较差
export function firstw(arr){
    // 过滤掉非正整数
    arr = arr.filter(item => item>0)
    // 正整数数组是不是为空
    if(arr.length){
      // 升序排序,方便从左往右取最小值arr[0]
      arr.sort((a, b) => a-b)
      // 如果第一个元素不为1,返回1
      if(arr[0]!==1){
        return 1
      }else{
        // 从左边开始遍历,只要下一个元素与当前元素的差值>1,则返回当前元素+1
        for(let i=0,len=arr.length; i<len; i++){
          if(arr[i+1]-arr[i]>1){
            return arr[i]+1
          }
        }
        // 如果数组是连续的正整数,则返回最后一个元素+1
        return arr.pop()+ 1
      }
    }else{
      return 1
    }
  }
// 法二: filter过滤不能省,利用选择排序依次拿到最小值,减少循环遍历次数,提高性能
  export function firstw1(arr){
    arr = arr.filter(item => item>0)
    console.log(arr.length)
    // 实现选择排序,先拿到最小值,如果第一个元素不是1直接返回1,如果是1,就要比相邻元素差值
    for(let i=0,len=arr.length,tmp; i<len; i++){
      for(let j=i+1; j<len; j++){
        if(arr[i]>arr[j]){
          tmp = arr[i]
          arr[i] = arr[j]
          arr[j] = tmp
        }
      }
      if(i>0){
        if(arr[i]-arr[i-1]>1){
          return arr[i-1]+1
        }
      }else{
        if(arr[0]!==1){
          return 1
        }
      }
    }
    return arr.length? arr.pop()+1: 1   
  }

# 递归 *****

  • 本质:每一个处理过程都是相同的,输入和输出是相同的,处理次数未知

# 复原IP地址

export default (str) => {
  //保存所有符合条件的ip
  let r = [];
  //递归函数
  let search = (cur, sub) => {
    if(cur.length === 4 && cur.join('') === str){
      r.push(cur.join('.'))
    }else{
      for(let i=0,len=Math.min(3, sub.length),tmp; i<len;i++){
        tmp= sub.substr(0, i+1);
        if(tmp>=0 && tmp<256){
          search(cur.concat([tmp]),sub.substr(i+1))
        }
      }
    }
  }
  search([], str);
  return r;
}

# 与所有单词相关联的字符串

# 数据结构(6)

# 堆 ****

# 根据字符出现频率排序

# 超级丑数

# 栈 ****

# 棒球比赛

# 最大矩形

# 队列 ****

# 设计循环队列

# 任务调度器

# 算法进阶(2)

# 贪心算法

# 买卖股票的最佳时机

# 柠檬水找零

# 动态规划

# 不同路径

# k站中转内最便宜的航班

# js手写map(方法)

Array.prototype.newMap = function(fn, context){
  let arr = this;
  let result = [];
  for(let i=0; i<arr.length; i++){
    result.push(fn.call(context, arr[i], i, arr))
  }
  return result;
}

# 求取a,b的最大公约数

export default function gcd(a,b){ if(b===0){ return a; }else{ return gcd(b, a%b) } }