总结自己最近遇到的编程题: 快排、冒泡(接近有序降得时间复杂度)、扁平化处理、过滤对象(将包含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'
。 - 对于
null
,typeof
同样返回'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:split
和 Number
先转成字符串再拆分为字符数组,map 将每个字符转成数字Number
js
const num = String(numArray).split('').map(Number)
方法2:toString
和 split
,使用String
类似
js
const num = numArray.toString().split('').map(Number);
方法3: Array.from
和 Number
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
:- 删除
'h'
→"orse"
- 删除
'o'
→"rse"
- 替换
'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;
}