前端常见算法和手写题汇总

200 阅读3分钟

一、算法

1、不重复字符的最长子串长度

题目:给定一个字符串,找出其中不含有重复字符的 最长子串 的长度。

var lengthOfLongestSubstring = function (s) {
    const occ = new Set(), // 哈希集合,记录每个字符是否出现过
        n = s.length
    let rk = -1, ans = 0 // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
    for (let i = 0; i < n; i++) {
        if (i != 0) {
            occ.delete(s.charAt(i - 1)) // 左指针向右移动一格,移除一个字符
        }
        while(rk + 1 < n && !occ.has(s.charAt(rk + 1))){
            occ.add(s.charAt(rk + 1)) // 不断地移动右指针
            ++rk
        }
        ans = Math.max(ans, rk - i + 1) // 第 i 到 rk 个字符是一个极长的无重复字符子串
    }
    return ans
}
console.log(lengthOfLongestSubstring('abcdeab')); // 5

2、斐波那契数列

题目:斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给你 n ,请计算 F(n) 。

写法1:

var fib = function(n) {
    if(n === 0) return 0;
    if(n === 1) return 1;
    let arr = [0,1];
    for(let i = 0; i < n; i++){
        let pre = arr[arr.length - 2],
            last = arr[arr.length - 1]
        arr.push(pre + last)
    }
    console.log(arr)
    return arr[n]
};

写法2:

function fibomacci(n) {
    if (n <= 1) return 1
    let arr = [1, 1]
    let i = n + 1 - 2 // 还要创建几位,n+1为位数 -2为去除数组固定的两个1后的位数
    while (i > 0) {
        let pre = arr[arr.length - 2],
            last = arr[arr.length - 1]
        arr.push(pre + last)
        i--
    }
    return arr[arr.length - 1]
}

3、反转链表

题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

var reverseList = function(head) {
    let prev = null,
        curr = head
    while(curr){
        let next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next
    }
    return prev
};

4、二叉树中和为某一值的路径

题目:输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

给定如下二叉树,以及目标和 target = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

返回

[
   [5,4,11,2],
   [5,8,4,5]
]

代码:

写法1:

var pathSum = function (root, sum) {
    var res = [], stack = [];
    function dfs(r, sum) {
        if (r == null) return;
        sum -= r.val;
        stack.push(r.val);
        if (r.left == null && r.right == null && sum == 0) res.push([...stack]);
        dfs(r.left, sum);
        dfs(r.right, sum);
        stack.pop();
    }
    dfs(root, sum);
    return res
};

写法2:

var pathSum = function(root, sum) {
    if (root === null) return [];
  const res = [];
  const DFS = (root, sum, tmp) => {
    if (root.val === sum && !root.left && !root.right) {
        res.push(tmp);
    }
    tmp.push(root.val);
    console.log(tmp.slice())
    if (root.left) DFS(root.left, sum - root.val, tmp.slice()); // tmp.slice()浅拷贝
    if (root.right) DFS(root.right, sum - root.val, tmp.slice());
  }
  DFS(root, sum, []);
  return res;
};

二、手写题

手写Promise.all

Promise.all = function all(promises) {
    var promiseNew,
        results = [],
        n = 0;
    promiseNew = new Promise(function (resolve, reject) {
        promises.forEach(function (promise, index) {
            promise.then(function (result) {
                n++;
                results[index] = result
                if (n >= promises.length) return resolve(results)
            }).catch(function (e) {
                return reject(e)
            })
        })
    })
    return promiseNew;
}

节流

function throttle(func, wait) {
    var timer = null,
        previours = 0, //上次触发时间
        result;
    return function proxy() {
        var now = +new Data(),
            remaining = wait - (now - previours), // 还差多久
            self = this,
            props = [].slice.call(arguments)
        if (remaining <= 0) {
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
            result = func.apply(self, props) 
            previours = +new Data()
        } else if (!timer) {
            timer = setTimeout(function () {
                if (timer) {
                    clearTimeout(timer)
                    timer = null
                }
                result = func.apply(self, props)
                previours = +new Data()
            }, remaining)
        }
        return result
    }
}
function fn() {
    console.log('ok');
}
throttle(fn, 500)

防抖

function debounce(fn, wait) {
    let timer = null,
        result
    return function () {
        let self = this,
            props = [].slice.call(arguments)
        if (timer) clearTimeout(timer)
        timer = setTimeout(function () {
            result = fn.apply(self, props)
        }, wait)
        return result
    }
}

冒泡排序

var arr = [3, 4, 1, 2]
function maopao(arr) {
    var max = arr.length - 1
    for (var i = 0; i < max; i++) {
        for (var j = 0; j < max - i; 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
}
maopao(arr)

快排

function quickSort(arr) {
    if(arr.length<1) return arr;
    var poivtIndex = Math.floor(arr.length/2)
    var poivt = arr.splice(poivtIndex, 1)[0]
    var left = []
    var right = []
    for(var i=0; i<arr.length; i++) {
       if(arr[i]<poivt) {
          left.push(arr[i])
       } else {
          right.push(arr[i])
       }
    }
   return quickSort(left).concat([poivt], quickSort(right))
 }
 var arr = [2,3,4,6,1,5]
 console.log(quickSort(arr))  // [1,2,3,4,5,6]

数字的千分位分隔

12345 --> 12,345

function fenge(str) {
    str = str + ''
    let arr = str.split('')
    for (let i = arr.length - 3; i > 0; i = i - 3) {
        arr.splice(i, 0, ',')
    }
    arr = arr.join('')
    console.log(arr)
}
fenge(1234567812345678)

格式化展示文件大小

// 方法一
function fileSize(size, toFixed) {
    let arr = ["Bytes", "KB", "MB", "GB", "TB"]
    let index = 0,
        srcsize = parseFloat(size)
    index = Math.floor(Math.log(srcsize) / Math.log(1024))
    let sizes = srcsize / Math.pow(1024, index)
    sizes = sizes.toFixed(2)
    console.log(sizes + arr[index])
    return sizes + arr[index]
}
fileSize(1023);// 1023b
fileSize(1024); // 1kb
fileSize(2000); // 1.953125kb
fileSize(2000, 2); // 1.95kb
fileSize(2 * 1024 * 1024); // 2mb
fileSize(1234 * 1024 * 1024 * 1024); // 1234tb

function fileSize(B, toFixed) {
    let arr = ['B', "KB", "MB", "GB", "TB"]
    let val = B / 1024
    let i = 0
    if (val < 1) {
        i = 0
        val = B + arr[i]
    } else if (val >= 1 && val < 2) {
        i = 1
        val = val + arr[i]
    } else {
        let temp = 1
        while (val >= 1024) {
            val = val / 1024
            temp++
        }
        val = val + arr[temp]
        console.log(val);
    }
}
fileSize(2456 * 1024 * 1024);

二分查找

非递归

const search = function (arr, value) {
    let start = 0,
        end = arr.length - 1

    while (start <= end) {
        let mid = Math.floor((start + end) / 2)
        if (arr[mid] == value) {
            return mid
        } else if (arr[mid] > value) {
            end = mid - 1
        } else {
            start = mid + 1
        }
    }
    return -1
}

递归

const search = (arr, value, start, end) => {
    if (start > end) {
        return -1
    }
    let mid = Math.floor((start + end) / 2)
    if (arr[mid] == value) {
        return mid
    } else if (arr[mid] > value) {
        end = mid - 1
        search(arr, value, start, end)
    } else {
        start = mid + 1
        search(arr, value, start, end)
    }
}

深克隆

function deepClone(obj){
    //过滤特殊情况
    if(obj === null) return null;
    if(typeof obj !== "Object") return obj;
    if(obj instanceof RegExp){
        return new RegExp(obj)
    }
    let newObj = obj instanceof Array?[]:{}
    for (let i in obj){
        if(obj.hasOwnProperty(i)){
            newObj[i] = deepClone(obj[i])
        }
    }
    return newObj;
}
let obj2 = deepClone(obj)

驼峰转短线分隔形式

function change(str){
    str = str.split('')
    let newStr=''
    for(let i=0;i<str.length;i++){
        if((str[i].charCodeAt(0) < 90) && (str[i].charCodeAt(0) > 65)){
           let s = str[i].toLowerCase()
            newStr = newStr + '-' + s
        }else{
            newStr= newStr + str[i]
        }
    }
    return newStr
}
let a = change('getElementById')
console.log(a) //get-element-by-id

async,await,promise 实现定时器效果,每隔一秒输出数组中的数字

let arr = [1, 1, 1, 1]
function sleep() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve()
        }, 1000)
    })
}
(async () => {
    for (let i of arr) {
        await sleep()
        console.log(i);
    }
})()