# 21-30

# 21、手写防抖节流-京东

function debounce(fn, delay) {
    let timer = null;
    return function () {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => fn.apply(this, arguments), delay);
    }
}

window.addEventListener(
    "scroll",
    debounce(() => {
        console.log(111);
    }, 1000)
);

function throttle(fn, delay) {
    let isFlag = false;
    return function () {
        if (isFlag) return;
        isFlag = true;
        setTimeout(() => {
            fn();
            isFlag = false;
        }, delay);
    }
}

window.addEventListener(
    "scroll",
    throttle(() => {
        console.log(111);
    }, 1000)
);

# 22、手写,将虚拟Dom转为真是Dom(类似的递归题-必考);

{
  tag: 'DIV',
  attrs:{
  id:'app'
  },
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
  <span>
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>

function _render(vnode) {
    if (typeof vnode === "number") {
        vnode = String(vnode);
    }
    if (typeof vnode === "string") {
        return document.createTextNode(vnode);
    }
    const dom = document.createElement(vnode.tag);
    if (vnode.attrs) {
        // for(let key in vnode.attrs) {
        //     dom.setAttribute(vnode.attrs[key]);
        // }
        Object.keys(vnode.attrs).forEach(key => {
            dom.setAttribute(key, vnode.attrs[key]);
        });
    }
    vnode.child.forEach(children => {
        dom.appedChild(_render(children));
    })
    return dom;
}

# 23、手写实现一个flatten方法-阿里

const obj = {
 a: {
        b: 1,
        c: 2,
        d: {e: 5}
    },
 b: [1, 3, {a: 2, b: 3}],
 c: 3
}

flatten(obj) 结果返回如下
// {
//  'a.b': 1,
//  'a.c': 2,
//  'a.d.e': 5,
//  'b[0]': 1,
//  'b[1]': 3,
//  'b[2].a': 2,
//  'b[2].b': 3
//   c: 3
// }

function isObject(val) {
    return typeof val === 'object' && val !== null;
}

function flatten(obj) {
    if (!isObject(obj)) return;
    let res = {};

    function dfs(cur, prefix) {
        if (isObject(cur)) {
            if (Array.isArray(cur)) {
                cur.forEach((item, index) => {
                    dfs(item, `${prefix}[${index}]`)
                })
            } else {
                for (let key in cur) {
                    dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`)
                }
            }
        } else {
            res[prefix] = cur;
        }
    }

    dfs(obj, "");
    return res;
}

# 24、手写判读字符串是否有效 - 小米

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

    左括号必须用相同类型的右括号闭合。
    左括号必须以正确的顺序闭合。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

function isValid(str) {
    if (!str || str.length % 2 === 1) return false;
    const obj = {
        '(': ')',
        '[': ']',
        '{': '}'
    }
    const queue = [];
    for (let i = 0; i < str.length; i++) {
        if (obj[str[i]]) {
            queue.push(str[i])
        } else {
            const cur = queue.shift();
            if (obj[cur] !== str[i]) {
                return false;
            }
        }
    }
    if (queue.length) return false;
    return true;
}

# 25、查找数组公共前缀-美团

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

function longestCommonPrefix(strArr) {
    const str = strs[0];
    let index = 0;
    while (index < strArr.length) {
        const strCur = str.slice(0, index + 1);
        for (let i = 0; i < strArr.length; i++) {
            if (!strs[i] && !strArr[i].startsWith(strCur)) {
                return str.slice(0, index);
            }
        }
        index++;
    }
    return str;
}

# 26、手写-字符串最长的不重复子串

题目描述

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。


示例 1:

输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示例 4:

输入: s = ""
输出: 0

function lengMax(s) {
    if (!s.length) return 0;
    let left = 0, map = new Map(), max = 0;
    for (let i = 0; i < s.length; i++) {
        if (map.has(s[i])) {
            left = Math.max(left, map.get(s[i]) + 1);
        }
        map.set(s[i], i);
        max = Math.max(max, i - left + 1);
    }
    return max;
}

# 27、手写-如何找到数组中第一个没出现的最小正整数 怎么优化(字节)

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3

示例 2:

输入:nums = [3,4,-1,1]
输出:2

示例 3:

输入:nums = [7,8,9,11,12]
输出:1

时间空间均为 O(n)

function firstMissingPositive(nums) {
    const set = new Set();
    for (let i = 0; i < nums.length; i++) {
        set.add(nums[i])
    }
    for (let i = 0; i < set.size; i++) {
        if (!set.has(i)) {
            return i;
        }
    }
    return set.size;
}

最终版 时间复杂度为 O(n) 并且只使用常数级别空间

function firstMissingPositive(nums) {
    for (let i = 0; i < nums.length; i++) {
        // 对1~nums.length范围内的元素进行安排 // 已经出现在理想位置的,就不用交换
        while (nums[i] > 0 && nums[i] < nums.length && nums[nums[i] - 1] !== nums[i]) {
            [nums[nums[i] - 1], nums[i]] = [nums[i], nums[nums[i] - 1]];
        }
    }
    // 现在期待的是 [1,2,3,...],如果遍历到不是放着该放的元素
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] != i + 1) {
            return i + 1;
        }
    }
    return nums.length + 1; // 发现元素 1~nums.length 占满了数组,一个没缺
}

28、手写-怎么在制定数据源里面生成一个长度为 n 的不重复随机数组 能有几种方法 时间复杂度多少(字节)

第一版 标记法 / 自定义属性法 时间复杂度为 O(n)

function getNums(testArray, n) {
    const map = new Map();
    for(let i = 0; i< n; i++) {
        const index = Math.floor(Math.random() * testArray.length);
        if(map.has(testArray[index])){
            i--;
            continue;
        }
        map.set(testArray[index], true);
    }
    return [...map.keys()];
}

第二版 交换法 时间复杂度为 O(n)

function getTenNum(testArray, n) {
  const cloneArr = [...testArray];
  let result = [];
  for (let i = 0; i < n; i++) {
    debugger;
    const ran = Math.floor(Math.random() * (cloneArr.length - i));
    result.push(cloneArr[ran]);
    cloneArr[ran] = cloneArr[cloneArr.length - i - 1];
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);

最终版 边遍历边删除 时间复杂度为 O(n)

function getTenNum(testArray, n) {
  const cloneArr = [...testArray];
  let result = [];
  for (let i = 0; i < n; ++i) {
    const random = Math.floor(Math.random() * cloneArr.length);
    const cur = cloneArr[random];
    result.push(cur);
    cloneArr.splice(random, 1);
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);

Last Updated: 5/22/2022, 4:32:01 PM