面试得知道的编程题 | 系列1:扁平化处理、过滤对象等👍

总结自己最近遇到的编程题: 快排、冒泡(接近有序降得时间复杂度)、扁平化处理、过滤对象(将包含null或数组的对象过滤出对象)、列表和数字之间转换、螺旋数组(顺时针转)

快排

性能接近o(n) 接近有序,退化o(n^2) 设定基准值,privot,递归实现快排

js 复制代码
function quickSort(arr) {
    if(arr.length <= 1) return arr; // 递归结束条件
    
    const privot = arr[Math.floor(arr.length / 2)]; // 中间
    const left = arr.filter(item => item < privot);
    const right = arr.filter(item => item > privot);
    const equal = arr.filter(item => item === privot);
    
    return quickSort(left).concat(equal, quickSort(right)); // concat 连接
}

冒泡

js 复制代码
function bubbleSort(arr) {
    const len = arr.length;
    for(let i = 0; i < len-1; i++){ // len-1 , 下面len-i-1 后i+1已经排好
        let swapped = false;
        for(let j = 0; j < len - i - 1; j++) {
            if(arr[j] > arr[j+1]) {
                // 交换 
                [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
                swapped = true; // 标记有交换
            }
        }
        if(!swapped) break; // 没有交换,提前结束
    }
    return arr
}

优化:如果接近有序。记录最后排序地方,后面不用再排序,并且设置lastSwapIndex 为0,减少比较次数。

js 复制代码
function advancedBubbleSort(arr) {
    let len = arr.length;
    let lastSwapIndex = len - 1;
    while (lastSwapIndex > 0) {
        let newLastSwapIndex = 0;
        for(let i = 0; i < lastSwapIndex; i++){
            if(arr[i] > arr[i+1]) {
                [arr[i],arr[i+1]] = [arr[i+1],arr[i]];
                newLastSwapIndex = i+1; // 记录最后交换的位置
            }
        }
        lastSwapIndex = newLastSwapIndex; // 缩小下一轮交换位置
    }
    return arr;
}

如果数组接近有序,优化很重要

扁平化

es6:flat(Infinity)

js 复制代码
const arr = [1, [2, [3, [4]]]];
const flatArr2 = arr.flat(2);
console.log(flatArr2); // [1, 2, 3, [4]]
const flatArr = arr.flat(Infinity);
console.log(flatArr); // [1, 2, 3, 4]

其他

js 复制代码
// 递归 + reduce
function flatter(arr) {
    return arr.reduce((pre,cur) => 
       pre.concat(Array.isArray(cur) ? flatter(cur) : cur),[])
}
// 递归+forEach
function flatter2(arr,res = []) {
    arr.forEach(item => {
        if(Array.isArray(item)) {
            flatter2(item,res)
        } else {
            res.push(item)
        } 
    })
    return res
}
// 队列 层级展开; 栈模拟也行(下面展示队列的思路)
function flatter3(arr) {
    const queue = [...arr]
    const res = [];
    while(queue.length) {
        const item = queue.shift()
        if(Array.isArray(item)){
            queue.unshift(...item); // 展开当前层级,插入对头
        } else {
            res.push(item)
        }
    }
    return res;
}
// 适用数组 
function flatter4(arr) {
    return arr.toString().split(',').map(Number)
}
// 适用字符串
function flatter5(arr) {
    return JSON.parse("["+JSON.stringify(arr).replace(/\[|\]/g,'')+"]")
}

过滤对象

为什么需要特殊处理对象?

在 JavaScript 中,typeof 操作符的行为对于某些类型并不直观:

  • 对于普通对象(如 { key: 'value' }),typeof 返回 'object'
  • 对于数组(如 [1, 2, 3]),typeof 也返回 'object'
  • 对于 nulltypeof 同样返回 'object'

因此,如果仅使用 typeof item === 'object' 来判断一个值是否是对象,会错误地将数组和 null 也识别为对象。

除了null typeof 靠谱;数组判断 Array.isArray()

js 复制代码
function filterArray(arr,type) {
    isObject = (item) => {
        return typeof item === 'object' && item !== null && !Array.isArray(item)
    }
    
    return arr.filter(item => {
        if(type === 'object') {
            return isObject(item);
        } else {
            return typeof item === type;
        }
    )

列表和数字转换

列表转数字

目标是将一个数组(如 [1, 2, 3, 4, 5])转换为对应的数字(如 12345)。 初学者:for 循环遍历列表

js 复制代码
let num3 = ''
// 循环拼接
for(let i = 0; i < numArray.length; i++) {
    num3 += numArray[i]
}
console.log(typeof parseInt(num3));

中级:join转字符串,parseInt 转数字

js 复制代码
const numArray = [1, 2, 3, 4, 5];
const num = parseInt(numArray.join(''))

高级:reduce 遍历累计,拼接到累计值acc上,可以增加额外操作

js 复制代码
const num = numArray.reduce((acc,cur) => acc+cur,'')
console.log(typeof parseInt(num2));

数字转列表

目标是将一个数字(如 123456789)转换为对应的数组(如 [1, 2, 3, 4, 5, 6, 7, 8, 9]

方法 1:splitNumber 先转成字符串再拆分为字符数组,map 将每个字符转成数字Number

js 复制代码
const num = String(numArray).split('').map(Number)

方法2:toStringsplit,使用String类似

js 复制代码
const num = numArray.toString().split('').map(Number);

方法3: Array.fromNumber Array.from 创建数组,第二个参数Number 将字符转成数字

js 复制代码
const num = Array.from(String(numArray),Number)

方法4:推荐 扩展运算符和map

js 复制代码
const num = [...String(numArrry)].map(Number);

编辑距离

编辑距离是指将一个字符串 word1 转换为另一个字符串 word2 所需的最少操作次数。允许的操作包括:

  • 插入:在字符串中插入一个字符。
  • 删除:从字符串中删除一个字符。
  • 替换:将字符串中的一个字符替换为另一个字符。

例如:

  • "horse" 转换为 "ros" 的编辑距离是 3

    1. 删除 'h'"orse"
    2. 删除 'o'"rse"
    3. 替换 'e''s'"ros"
js 复制代码
// 编辑距离
function minDistance(word1, word2) {
    const m = word1.length;
    const n = word2.length;
    const dp = Array.from({length:m+1},()=>Array(n+1).fill(0))
    // 初始化 i
    for(let i=0;i<m;i++){
        dp[i][0]=i;
    }
    for(let j=0;j<n;j++) {
        dp[0][j]=j;
    }
    for (let i = 1; i <= m; i++) { 
        for (let j = 1; j <= n; j++) { 
            if (word1[i - 1] === word2[j - 1]) { 
                dp[i][j] = dp[i - 1][j - 1]; 
            } else { 
                dp[i][j] = Math.min( 
                    dp[i - 1][j - 1] + 1, // 替换 
                    dp[i - 1][j] + 1, // 删除 
                    dp[i][j - 1] + 1 // 插入
              ); 
            } 
         }
     }
     
     return dp[m][n];
}

数组

螺旋

js 复制代码
function spiralOrder(matrix, n) {
    let top = 0;
    let bottom = n - 1;
    let left = 0;
    let right = n - 1;
    let res = []

    while(top <= bottom && left <= right) {
        for(let i = left; i <= right; i++) {
            res.push(matrix[top][i])
        }
        top++;// 下一行
        // 或 top > bottom break出来
        for(let i = top; i <= bottom;i++) {
            res.push(matrix[i][right])
        }
        right--;// 左边一列
        if(top <= bottom) { // 如果top > bottom break出来
            for(let i = right;i>=left;i--) {
                res.push(matrix[bottom][i])
            }
        }
        bottom--;// 上一行
        if(left <= right) { 
            for(let i = bottom;i>=top;i--) {
                res.push(matrix[i][left])
            }
        }
        left++;// 右移动
    }
    return res;
}
相关推荐
Fanxt_Ja22 分钟前
【LeetCode】算法详解#2 ---和为k的子数组
java·数据结构·算法·leetcode·idea·哈希表
熊峰峰28 分钟前
1.3 斐波那契数列模型:LeetCode 746. 使用最小花费爬楼梯
算法·leetcode·动态规划
SuperYing37 分钟前
前端候选人突围指南:让面试官主动追着要简历的五大特质(个人总结版)
前端·面试
藍海琴泉43 分钟前
贪心算法经典应用:最优答疑调度策略详解与Python实现
算法·贪心算法
脏脏a1 小时前
C语言函数递归
c语言·算法
百渡ovO1 小时前
【蓝桥杯】每日练习 Day 16,17
c++·算法·图论
梁下轻语的秋缘1 小时前
每日c/c++题 备战蓝桥杯(二分答案模版)
c语言·c++·学习·算法·蓝桥杯
Moment1 小时前
前端性能指标 —— CLS
前端·javascript·面试
溟洵1 小时前
【C/C++算法】从浅到深学习---分治算法之快排思想(图文兼备 + 源码详解)
c语言·c++·算法
修修修也1 小时前
【算法手记7】拼三角
数据结构·学习·算法·刷题