前端算法


对字符串、数组的查询调用,一般思路是将字符串、数组提取到对象,再操控对象。

字符串中出现最多次的字符以及其次数

核心算法:
1、将字符存储在一个对象内,给其当属性名,属性值为出现的次数
①利用charAt()遍历字符串
②把每个字符都存储给一个对象,(即当做改对象的属性名)
③判断该对象是否有该属性,没有,赋值1;有,则+1
2、取对象属性值最大值,即可得到字符串中出现最多次的字符以及其出现的次数
①遍历对象
②取最大值

//字符串中最多次的字符以及其次数
var str1 = 'abcabaabcaba';
var obj = {} 

function findMaxDuplicateChar(str) {
  if (str.length == 1) {
	return str
  }
  let obj = {}
  for (i = 0; i < str.length; i++) {
    let char = str.cahrAt(i)
    if(obj[char]) {
      obj[char]++
    } else {
      obj[char] = 1
    }
  }
  // 遍历对象
  let maxChar = ''
  let maxValue = 1
  for(var k in obj) {
    if(obj[k] >= maxValue) {
      maxChar = k
      maxValue = charObj[k]
    }
  }
  return [maxChar, maxChar]
}

判断一个单词是否是回文

回文:指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情趣,叫做回文,也叫回环。比如 mamam redivider .
核心算法:
利用数组的翻转方式生成新字符串,与原字符串比较。
①字符串 —> 数组
②数组翻转
③数组 —> 字符串

function checkPalindrom(str) {  
    return str == str.split('').reverse().join('');
}

找出字符串中最长回文子串

详解传送门.

//中心扩展法
var longestPalindrome = function(s) {
    if(!s || s.length < 2){
        return s
    }
    var start = 0
    var end = 0
    var n = s.length
    //中心扩展
    function centerExpend(left,right){
        while(left >=0 && right < n && s[left] == s[right]){
            left--
            right++
        }
        return right-left-1
    }
    for(var i=0;i<n;i++){
    	//回文有两种情况,一种是aba,一种是abba
        var len1 = centerExpend(i,i)
        var len2 = centerExpend(i,i+1)
        //两种组合取最大的回文串长度
        var maxLen = Math.max(len1,len2)
        if(maxLen > end-start){
            //更新最大回文串的首位字符索引
            start = i - ((maxLen-1) >> 1)  //>>右移操作
            end = i + (maxLen >> 1)
        }
    }
    return s.substring(start,end+1)
};

数组去重

输入[1,4,5,7,1,8,7,6]
输出[1,4,5,7,8,6]
有两种写法:
①利用对象查找
②利用数组的indexOf()查找
方法一:

function duplicateRemoval(arr) {
  let obj = {}
  let newArr = []
  for(let i = 0; i < arr.length; i++) {
    if(!obj[arr[i]]){
      obj[arr[i]] = true
      newArr.push(arr[i])
    }
  }
  return newArr
}

方法二.

快速排序

在这里插入图片描述
核心算法:
将数组元素与某一元素比较(一般用为arr[0]),将小于它的元素放在左数组,大于它的元素放在右数组,然后递归进行上一次左右数组的操作,返回合并的数组就是已经排好顺序的数组了。

function quickSort(arr) {
  if(arr.length <= 1) {
    return arr
  }

  let leftArr = []
  let rightArr = []
  let q = arr[0] // 用来比较的元素
  // 第一个元素arr[0]不参与比较,不然它会一直卡在第一个位置
  for(let i = 1;i < arr.length; i++) {
    if(arr[i] < q) {
      leftArr.push(arr[i])
    } else {
      rightArr.push(arr[i])
    }
  }
  // concat 连接数组
  return [].concat(quickSort(leftArr), q, quickSort(rightArr))
}

不借助临时变量,将两个整数进行对换

输入 a = 2,b = 4
输出 a = 4,b = 2
核心算法:
主要是利用 +、- 去进行运算,类似 a = a + ( b - a) 实际上等同于最后 的 a = b;

function swap(a, b) {
  b = b - a
  a = a + b // a = a + b = 原a + (原b - 原a) = 原b
  b = a - b // b = a - b = 原b - (原b - 原a) = 原a
  return [a, b]
}

输出指定长度的随机字符串

核心算法:
Math.random() (产生[0,1]之间的随机数)和 Math.floor() (向下取整)

function randomString(n) {  
  let str = 'abcdefghijklmnopqrstuvwxyz9876543210' // 先给出26个字母 + 10个个位数数字
  let tmp = ''
  let i = 0
  let l = str.length
  for (i = 0; i < n; i++) {
    tmp += str.charAt(Math.floor(Math.random() * l));
  }
  return tmp;
}

在树中查找某个结点并返回该节点路径与叶节点

给定一个树,给定一个节点id,返回从root到该节点的path、以及该节点的所有叶节点id。
叶节点:最末端的节点。

const exampleTree = {
  _id: 1,
  children: [{
    _id: 2,
    children: [{
      _id: 4,
      children: [{
        _id: 7,
        children: []
      }]
    }, {
      _id: 5,
      children: []
    }]
  }, {
    _id: 3,
    children: [{
      _id: 6,
      children: [{
        _id: 8,
        children: [{
          _id: 10,
          children: []
        }]
      }, {
        _id: 9,
        children: []
      }]
    }]
  }]
}
//主执行函数
function searchTree(tree, id) {
  let res = findNode(tree, id)
  //边界处理,输入的id不存在相对应的节点时
  if (res == undefined) {
    return '在该树的中没有相对应的id的节点'
  }

  res.path.unshift(tree._id)
  let path = res.path.join('-')
  let node = res.node // 返回的以该节点为起点的树
  let leaves = findLeaves(node)
  return {
    path,
    leaves
  }
}

// 深度遍历查找目标节点及缓存相关路径
// 先往某一个节点一直往下查找,找不到再反着一层一层再往下查找
function findNode(tree, id) {
  if (tree._id == id) {
    console.log(123) // 找到节点
    return {
      path: [],
      node: tree
    }
  }
  console.log(321) // 找不到节点
  let res
  for (let i = 0; i < tree.children.length; i++) {
    res = findNode(tree.children[i], id)
    if (res != undefined) {
      res.path.unshift(tree.children[i]._id)
      return res
    }
  }
  return undefined
}

// 递归获取叶节点
function findLeaves(node) {
  if (node.children.length == 0) {
    return [node._id]
  }
  let leaves = []
  for (let i = 0; i < node.children.length; i++) {
    res = findLeaves(node.children[i])
    leaves = res.concat(leaves)
  }
  return leaves
}
console.log(searchTree(exampleTree, 6));

在这里插入图片描述
在这里插入图片描述
查找路径:
在这里插入图片描述

二叉树

实现类似getElementsByClassName 的功能

子串最长无重复字符长度

“vaaabcdde” 子串最长无重复字符长度为4,即"abcd"

var lengthOfLongestSubstring = function(s) {
  var res = 0 // 用于存放当前最长无重复子串的长度
  var str = "" // 用于存放无重复子串
  for(var i = 0; i < s.length; i++) {
    var char = s.charAt(i)
    var index = str.indexOf(char)
    if(index === -1) {
      str += char
      res = res < str.length ? str.length : res
    } else {
      // 对无重复子串进行更新
      // 遇到重复字符,对str进行更新,因为有res保存最长的长度,所以可以覆盖,只需比较大小即可
      str = char
    }
  }
  return res
}

仅反转字母,非字母保留

给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。
示例:ab12cd 返回 dc12ba

思路:
1.先保留非字母位置
2.从反转数组最后一个位置开始找undefined,找到则将原数组的第一个字母放在该位置
3.依此类推
PS:大写字母的ASCII码:65 ~ 90,小写字母:97 ~ 122

var reverseOnlyLetters = function(S) {
  let arr = Array(S.length) // 用来存放反转的字符
  for (let i = 0; i < S.length; i++) {
    let ascii = S[i].charCodeAt()  // 获取原字符串的字符,用来找出字母与非字母
    if ((ascii < 65) || (ascii > 90 && ascii < 97)) {
      arr[i] = S[i]  // 先将不是字母的字符放好(保留位置)
    }
  }
  let j = S.length - 1
  for (let i = 0; i < S.length; i++) {
    let ascii = S[i].charCodeAt()
    while (arr[j] !== undefined) { // 从最末端查找是否是字母,不是则继续找(j--),是则确定了第一个字母位置
      j--
    }
    if ((ascii >= 65 && ascii <= 90) || (ascii >= 97 && ascii <=122)) {
      arr[j] = S[i]
    }
  }
  return arr.join('')
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值