前端——算法

前言

和数据结构一样,考算法题也备受面试官的青睐,很多时候我们可以根据题目的特点,甚至 可以和面试官讨论选择适合的方法编程,通常排序和查找是面试时考查算法的重点,二分查找,归并、快排要能做到随时准确,完整的写出它们的代码。
影响代码规范性的因素:书写、布局、命名
代码的完整性:边界判断一定要加上!

数组篇:

数组的基础知识

let arr1 = [1, 2, 10, 30]
let arr2 = [3, 4, 50, 90]
let arr3 = ['banana', 'apple', 'peach']
// arr1.concat(arr2) // [ 1, 2, 10, 30, 3, 4, 50, 90 ] 合并数组
// const a = arr1.entries() // Object [Array Iterator] {} 返回一个数组迭代对象,可用for of遍历
// arr1.fill('bob')  // [ 'bob', 'bob', 'bob', 'bob' ] 使用一个固定值来填充数组,改变原数组
// const flag = arr1.every(item => { return item >= 1 }) // true 数组内每一个元素都满足>=1返回true,有一个不满足就返回flase,并不再遍历,不改变原数组
// const flag = arr1.some(item => { return item > 11 }) // true 数组内只要有一个元素满足条件就返回true,不再遍历数组,都不满足返回false,不改变原数组
// const newArr = arr1.filter(item => { return item > 6 }) // [ 10, 30 ] 返回满足判断条件的元素组成的数组,不改变原数组
// const target = arr1.find(item => { return item > 99 }) // 10 返回满足条件的第一个元素,找到目标元素便不再遍历,无就返回undefind,不改变原数组
// const targetIndex = arr1.findIndex(item => {return item >= 10}) // 2 返回满足条件的元素的索引,无就返回-1
// const newArr = arr1.forEach(item =>{ if(item===2) return ;console.log('执行')}) // 执行 执行 执行 将数组内的每个元素都执行一次函数,这里的return相当于continue,跳出循环要使用try catch实现,改变元素组,没有返回值
try{
   
        array.forEach(function(item,index){
   
                if(item == "third"){
   
                        throw new Error("ending");//报错,就跳出循环
                }else{
   
                        console.log(item);
                }
        })
}catch(e){
   
        if(e.message == "ending"){
   
                console.log("结束了") ;
        }
}
// const newArr2 = Array.from('HBGSV') // [ 'H', 'B', 'G', 'S', 'V' ]将一个字符串转化为数组
// const newArr = new Set(arr1)
// const newArr2 = Array.from(newArr, x => x * 10) // [ 10, 20, 100, 300 ]将map结构转化为数组结构,第二个参数是一个函数,数组内的每一个数都会执行它
// const flag = arr1.includes(2) // true 看数组内是否包含2这个元素,返回布尔值
// const flag = arr1.indexOf(10) // 2 返回指定元素在数组内的索引位置,无就返回-1
// const flag = Array.isArray(arr1) // true 判断一个对象是否是一个数组
// const string1 = arr1.join() // 1,2,10,30 将一个数组转化为一个字符串,参数不写默认以逗号分隔
// arr1.keys() // Object [Array Iterator] {}返回一个实现Iterator接口的对象,需要调用.next() // { value: 0, done: false } .value: // 0
// const index = arr1.lastIndexOf(10) // 2 返回目标元素在数组里出现的最后一个位置
// const newArr = arr1.map(item => { return item * 2 }) // [ 2, 4, 20, 60 ] 返回处理过的数组,不改变原数组
// const popRes = arr1.pop() // 30 删除数组最后一个元素,并返回被删除的元素
// const newArrLength = arr1.push(1,2) // 6 向数组的末尾添加元素,并返回新数组的长度
// const arrTotal = arr1.reduce((total, current) => { return total + current }, 0) // 43 返回数组内所有元素计算的结果(从左到右) 第一个参数是一个函数,函数有两个参数,分别是:上一次相加的结果和当前正要加的值,另一个参数是相加的初始值
// const arrTotal = arr1.reduceRight((total, current) => { return total - current }, 0) // -43 功能和上一个一样,不同之处是它(从右到左)
// const newArr = arr1.reverse() // [ 30, 10, 2, 1 ] 颠倒数组中的顺序,返回颠倒顺序的数组,并改变原数组!!
// const newArr = arr3.sort() // [ 'apple', 'banana', 'peach' ] 对数组内的元素(字母)进行升序排序,但是数字排序会出错(下一个),返回排好顺序的数组,并改变原数组!!
// const newArr = arr1.sort((a, b) => { return a - b }) // [ 1, 2, 10, 30 ] 对数组内的数字执行排序时要传入一个函数,a-b为升序,b-a为降序,返回排好顺序的数组,并改变原数组!!
// const shiftRes = arr1.shift() // 1 删除并返回数组的第一个元素 改变原数组
// const newArrLength = arr1.unshift(99) // 5 向数组的开头添加元素,返回数组的新长度 改变原数组
// const newArr = arr1.slice(0, 2) // [ 1, 2 ] 两个参数分别是切的开始位置和结束位置,返回由选定的元素组成的新数组,不改变原数组
// array.splice(index,howmany,item1,.....,itemX) // index:删除或添加函数的位置;howmany:从index位置删除howmany个元素(必须),不写就直接删除index之后的所有元素(非必须);item1,.....:为添加的元素,不写就不添加(非必须),函数返回被删除的元素
// const newArr = arr1.splice(2,0,99) // [] 返回值为删除的元素所组成的数组,这里我们从数组为2的位置插入(删除)元素,删除0个元素,添加99这个元素,改变原素组!!
// const newString = arr1.toString() // 1,2,10,30 将数组转化为字符串,以逗号分隔数组元素,不改变原数组
// const newString = arr1.valueOf() // 返回元素本身[ 1, 2, 10, 30 ],运算是先调用valueOf再调用toString,日期对象的话会返回1970 年 1 月 1 日到当前对象的毫秒数

1、找出数组内重复的的数字

问题描述:找出数组内重复的的数字,有便返回重复的值,无便返回-1,例如[3,4,5,3,7,9,4],返回3或4均正确。
思路:利用对象的属性名是唯一的

function getRes() {
   
  const arr = [3, 4, 5, 3, 7, 9, 4]
  const len =  arr.length
  const obj = {
   }
  let resArr = []
  if (Array.isArray(arr) && len > 0) {
   
    for (let i = 0; i < len; i++) {
    
      if (obj[arr[i]] === undefined) {
   
        obj[arr[i]] = 1
      }
      else {
   
        obj[arr[i]]++
      }
    }

    for (let key in obj) {
   
      if (obj[key] >= 2) {
   
        resArr.push(key)
      }
    }

    return resArr.length === 0 ? -1 : resArr[0]
  }
  else {
   
    return -1
  }
}

console.log(getRes()) // 3

2、构建乘积数组

问题描述:给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],
其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]A[n-1](说白了:除掉i之后,数组[i]左边右边的数的乘积)。
不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],
B[n-1] = A[0] * A[1] * … * A[n-2];)
对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。

思路:先将前i个数的乘积求出来(前缀乘),再将后i个数的乘积求出来(后缀乘积),最后将前缀*后缀既得B[i]。


function getRes() {
   
  let arr = [1, 2, 3, 4, 5] // 输入数组
  
  let preArr = []  // 前缀乘积
  preArr[0] = 1
  for (let i = 1; i < arr.length; i++) {
   
    preArr[i] = preArr[i - 1] * arr[i - 1]
  }

  let sufArr = [] // 后缀乘积
  sufArr[arr.length - 1] = 1
  for (let j = arr.length - 2; j >= 0; j--) {
   
    sufArr[j] = sufArr[j + 1] * arr[j + 1]
  }

  let resArr = [] // 结果数组
  for (let i = 0; i < arr.length; i++) {
   
    resArr[i] = preArr[i] * sufArr[i]
  }

  return resArr
}

console.log(getRes())

3、二维数组中的查找

问题描述:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。

给定 target = 3,返回 false。
思路:从右上角(左下角也可以,因为这样我们没走一步都能淘汰一行或一列,但是右下角和左上角每走一步却不能淘汰一行或一列效率不高)开始查找,先往左走,遇到比target大的数就继续左走,遇到比target小的数就往下走,就能找到target,循环完还找不到就说明没有,返回return。最后ES6中有将多维数组转化为一维数组的方法,arr.flat(数组的维度),例如[[1, 2, 8, 9], [2, 4, 9, 12, [1,1,1]]]. flat( 2 ) // [1, 2, 8, 9, 2,4, 9, 12, 1, 1,1] ,对二维没有思路的话,转为一维就很简单了,如果面试官能让这样解的话。。。

function Find(target, array) {
   
  if (Array.isArray(array) && array.length > 0 && Array.isArray(array[0]) && array[0].length > 0) {
   
    let x = array.length // 获取二维数组的行数
    let y = array[0].length // 获取二维数组的列数
    // 从二维数组的右上角开始查找target
    let i = array[0].length - 1 // 列位置
    let j = 0 // 行位置
    while (i >= 0 && j <= x - 1) {
   
      if (target < array[i][j]) {
    // 如果目标值前一个数小,往左走
        i--
      }
      else if (target > array[i][j]) {
    // 如果目标值比下一个数大,往下走
        j++
      }
      else {
    // 不大也不小了,说明相等了,找到目标值,返回true
        return true
      }
    }
    return false // 循环完没找到,说明没有,return false
  }
}
const res = Find(15, [
  [1, 2, 8, 9],
  [2, 4, 9, 12],
  [4, 5, 10, 13],
  [6, 8, 11, 15]
])
console.log(res) // true

4、两数之和

问题描述:给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
假设给出的数组中只存在唯一解
例如:
给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2

思路:最开始肯定会使用循环暴力解,两个for循环很快解出来了,但是去看最优解才知道,这道题可以使用hash表的方式解出来,每一次循环的时候都将数组中的值和索引值放到hash表中,target依次减去数组中的数,如果得到的结果恰巧hash表中已经存进去了(就是6-2 = 4 ;4在hash表中还没有将2存进去,但是下次轮询 6-4 = 2 ,2刚好在上一轮被放进去了,就有,得出结果数组 ),那么就找到了,返回hash表中的索引和当前遍历的索引即可。

function twoSum(numbers, target) {
   
let len =  numbers.length 
if (Array.isArray(numbers) && len > 0){
   
let resArr = new Map()
  let res = undefined
  for (let i = 0; i < len; i++) {
   
    res = target - numbers[i]
    if (resArr.has(res)) {
   
      return [resArr.get(res) + 1, i + 1]
    }
    resArr.set(numbers[i],i)
  }
  }
}
twoSum([3, 2, 4], 6) // [ 2, 3 ]

5、将数组中的0放到数组的末尾

问题描述:将数组中的0放到数组的末尾
例如:输入:[ 9, 10, 0, 1, 2, 2, 3, 0,12] 输出:[ 9, 10, 1, 2, 2, 3, 12, 0, 0 ]
思想:用两个指针,例如是指针A与指针B,指针A跟随for循环正常指到数组中的每一项,而指针B当指针A指的不是0才跟着往下指,一旦B指到数组中的0就停止走动,当指针A指到下一个不是0的数值时,就和指针B指到的值交换,指针A直接赋值为0,渐渐把不是0的值放在数组的前面,0放到数组的后面

function twoSum(nums) {
   
  let tem = 0
  for (let i = 0; i < nums.length; i++) {
   
    if (nums[i] !== 0) {
    // 当tem指到0了tem就不移动,让i++
      if (nums[tem] == 0) {
   
        nums[tem] = nums[i]
        nums[i] = 0
      }
      tem++ // 当指到数组中不是0的数tem才继续移动
    }
  }
  return nums
}

twoSum([9, 10, 1, 0, 2, 2, 0, 3, 12])

6、斐波那契数列

问题描述:大家都知道斐波那契数列(除了前三项,之后项都等于前两项之和,现在要求输入一个整数n,请你输出斐波那契数列的第n项
思路:可以用递归实现,优点:代码可读性高,缺点:时间复杂度和空间复杂度高,重复计算部分较多;所以改用循环加三数实现

function getRes(n) {
   
  if (n < 2) {
   
    return n
  }
  let first = 1;
  let second = 1;
  let res = 0;
  for (let i = 2; i < n; i++) {
   
    res = first + second
    first = second
    second = res
  }
  return res
}

6.1青蛙跳台阶问题

问题描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
分析:
当n=1时结果为1
当n=2时结果为2
当n=3时结果为3
当n=4时结果为5
当n=5时结果为8

可以得到规律当n>=3时有 f(3) = f(2) + f(1)即f(n) = f(n-1) + f(n-2);也就是斐波那契数列

function qwJump(n) {
   
    if (n <= 1) {
   
        return 1
    }
    if (n === 2) {
   
        return 2
    }
    let res = 0
    let t1 = 1
    let t2 = 2
    for (let i = 3; i <= n; i++) 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值