数据处理手写题
1. 日期格式化函数
function dateFormat = (date, format) => {
const day = date.getDate()
const month = date.getMonth() + 1
const year = date.getFullYear()
let res = format.replace(/yyyy/, year)
res = format.replace(/MM/, month)
res = format.replace(/dd/, day)
return res
}
2. 交换 a,b 的值,不能用临时变量
let a = 1
let b = 2
a = a - b // 拿到 b 达到 a 需要加的 差值
b = b + a // b 加上了这个差值,值就变成了 a
a = b - a // 减去 这个差值 就是 b
3. 数组的乱序输出
for(let i=0; i<arr.length; i++){
const random = Math.floor(Math.random() * (arr.length-1-i)) + i
[arr[i], arr[random]] = [arr[random], arr[i]]
}
4. 数组元素求和
// 一维数组
function sums(arr){
return arr.reduce((total, item) => total += item, 0)
}
// 多维数组
function sums(arr){
return arr.toString().splice(',').reduce((total, item) => total += Number(item), 0)
}
5. 数组去重
// Set
function uniqueArray(arr){
return Array.from(new Set(arr))
}
// Map
function uniqueArray(arr){
let map = {}
let res = []
for(let i=0; i<arr.length; i++){
if(!map.getOwnProperty(arr[i])) {
map[arr[i]] = 1
res.push(arr[i])
}
}
return res
}
// js 实现有序数组原地去重
function noRepeat(arr){
for(let i=0; i<arr.length-1; i++){
for(let j=i+1; j<arr.length; j++){
if(arr[j]===arr[i]){
arr.splice(j, 1)
j--
}
}
}
return arr
}
function noRepeat(arr){
for(let i=0; i<arr.length; i++){
if(arr.indexOf(arr[i]) !== i){
arr.splice(i, 1)
i--
}
}
return arr
}
function noRepeat(arr){
return arr.filter((value, index)=>{
return arr.indexof(value) !== index
})
}
6. 合并多个 Map
function mapConcat<T, U>(...maps: Map<T, U>[]): Map<T, U> {
const result = new Map<T, U>();
for (const map of maps) {
for (const [key, value] of map) {
result.set(key, value);
}
}
return result;
}
7. 嵌套括号
给你一个字符串,只包含{} [] (),字符串会随机嵌套,请你帮忙判断一下字符串是否闭合,是否合法;
如果闭合且合法输出true,否则输出false
合法规则:{} [] () 依次嵌套,可同级嵌套;
示例 1:
输入:arr = {[()]} 闭合且合法
输出:true
示例 2:
输入:arr = {[(())]} 闭合且合法
输出:true
示例 3:
输入:arr = {[()} 未闭合
输出:false
示例 4:
输入:arr = {([()])} 出现()嵌套[]的情况,不合法
输出:false
function isValid(s) {
const stack = [];
const map = {
'(': ')',
'[': ']',
'{': '}'
};
for (let i = 0; i < s.length; i++) {
const item = s[i]
if (item === '{' && !stack.includes('[') && !stack.includes('(')) {
stack.push(item);
} else if (item === '[' && !stack.includes('(')) {
stack.push(item);
} else if (item === '(') {
stack.push(item);
} else {
let topElement = stack.length !== 0 ? stack.pop() : '#';
if (item !== map[topElement]) {
return false;
}
}
}
return !stack.length;
}
console.log(isValid('{[()]}')); // 输出:true
console.log(isValid('{[(())]}')); // 输出:true
console.log(isValid('{[()}')); // 输出:false
console.log(isValid('{([()])}')); // 输出:false
8. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入: ["flower","flow","flight"]
输出: "fl"
示例 2:
输入: ["dog","racecar","car"]
输出: ""
function longestCommonPrefix(strs) {
if (!strs.length) return "";
let prefix = strs[0];
for (let i = 1; i < strs.length; i++) {
while (strs[i].indexOf(prefix) !== 0) {
prefix = prefix.substring(0, prefix.length - 1);
if (!prefix) return "";
}
}
return prefix;
}
// 测试用例
console.log(longestCommonPrefix(["flower","flow","flight"])); // 输出: "fl"
console.log(longestCommonPrefix(["dog","racecar","car"])); // 输出: ""
9. deleteABCD
输入是一个仅由大写英文字母组成的字符串。您需要把字符串中所有的连续 "AB" 和 "CD" 子串进行删除,直到不再包含连续 "AB" 和 "CD" 子串后,返回字符串的长度。
注意:
1.删除字符串后可能会导致新的连续"AB"和"CD"字符串,例如AABB,最终返回为0。 2.只需要最后返回正确结果即可,不需要真正对字符串进行删除操作
代码复杂度要求:o(n)
例子:
- s = AAABCDBE
- 删除AB
- AACDBE
- 删除CD
- AABE
- 删除AB
- AE
function remove(s) {
let stack = [];
for(let i=0; i<s.length; i++) {
if(stack.length > 0 && ((s[i] === 'B' && stack[stack.length-1] === 'A') || (s[i] === 'D' && stack[stack.length-1] === 'C'))) {
stack.pop();
} else {
stack.push(s[i]);
}
}
return stack.length;
}
let s = "AAABCDBE";
console.log(remove(s)); // 输出:2
10. 数组中对称项有几个
const arr = ['AB', 'BA', 'XX', 'BA', 'AB', 'CD', 'XX', 'AB']
- (i, j) i < j
- arr[i] 和 arr[j] 是对称的
- 输出有多少对?7
function countPairs(arr) {
const map = new Map();
let count = 0;
for (let i = 0; i < arr.length; i++) {
const str = arr[i];
const reversedStr = str.split('').reverse().join('');
if (map.has(reversedStr)) {
count += map.get(reversedStr);
}
if (!map.has(str)) map.set(str, 0);
map.set(str, map.get(str) + 1);
}
return count;
}
const arr = ['AB', 'BA', 'XX', 'BA', 'AB', 'CD', 'XX', 'AB'];
console.log(countPairs(arr)); // 输出结果为7
11. 股票最大利润
- 数组
- 输入:[7,1,5,3,6,4]
- 输出:5
- 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
- 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
function maxProfit(prices) {
let minPrice = Infinity;
let maxProfit = 0;
for (let i = 0; i < prices.length; i++) {
if (prices[i] < minPrice) {
minPrice = prices[i];
} else if (prices[i] - minPrice > maxProfit) {
maxProfit = prices[i] - minPrice;
}
}
return maxProfit;
}
console.log(maxProfit([7,1,5,3,6,4])); // 输出: 5
12. 字符串翻转
function reverse(str){
return str.split("").reverse().join("")
}
13. 千分位隔开,钱,金额,money
function format(num){
return num.toLocaleString()
}
function format(num){
return new Intl.NumberFormat().format(num)
}
function format(num){
num = num.toFixed ? num.toFixed(2) : num
const arr = (num + '').split('.')
const int = arr[0].split('')
const decimals = arr[1] || '00'
let res = ''
int.reverse().forEach((item, index) => {
if(index !== 0 && index % 3 === 0){
res = item + ',' + res
} else {
res = item + res
}
})
return res + '.' + decimals
}
14. 类数组转化为数组
Array.prototype.slice.call(arrayLike);
Array.prototype.splice.call(arrayLike, 0);
Array.prototype.concat.apply([], arrayLike);
Array.from(arrayLike);
15. 对象转树形
// 转换前:
source = [
{
id: 1,
pid: 0,
name: 'body'
},
{
id: 2,
pid: 1,
name: 'title'
},
{
id: 3,
pid: 2,
name: 'div'
}
]
// 转换为:
tree = [{
id: 1,
pid: 0,
name: 'body',
children: [{
id: 2,
pid: 1,
name: 'title',
children: [{
id: 3,
pid: 1,
name: 'div'
}]
}
}]
function jsonToTree(data){
let res = []
if(!Array.isArray(data)){
return res
}
let map = {}
data.forEach(item => {
map[item.id] = item
})
data.forEach(item => {
const parent = map[item.pid]
if(parent){
(parent.children || (parent.children = [])).push(item)
}else{
res.push(item)
}
})
}
16. 树转数组
function treeToArray(tree){
let res = []
res = getItem(tree, res)
return res
}
function getItem(tree, res){
for(let i=0; i<tree.length; i++){
let item = tree[i]
if(item.children){
getItem(item.children, res)
delete item.children
}
res.push(item)
}
return res
}
function treeToArray(tree){
let queue = []
queue = queue.concat(tree)
let res = []
while(queue.length){
let item = queue.shift()
if(item.children){
queue = queue.concat(item.children)
delete item.children
}
res.push(item)
}
return res
}
17. 数组转树
function arrayToTree(arr, pid){
let res = []
getItem(arr, pid, res)
return res
}
function getItem(arr, pid, res){
for(let i=0; i<arr.length; i++){
let item = arr[i]
if(item.pid === pid){
let newItem = { ...item, children: []}
res.push(newItem)
getItem(arr, item.id, newItem.children)
}
}
}
18. 解析 URL Params 为对象
function parseQueryParam(url){
let param = {}
let arr = url.split('?')
if(arr.length <= 1){
return param
}
arr = arr[1].split('&')
for(let i=0; i<arr.length; i++){
const keyVal = arr[i].split('=')
param[keyVal[0]] = keyVal[1]
}
return param
}
19. 数组元素偏移
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
function moveArray(arr, index, offset){
const output = [...arr];
let element = output.splice(index, 1)[0]
let moveStep = index + offset
if(moveStep < 0) moveStep++
if(moveStep >= arr.length) moveStep -= arr.length
output.splice(moveStep, 0, element)
return output
}
console.log(moveArray(numbers, 3, -5));
20. 函数 fn({start,success,fail}) 可以 catch/then 的链式调用
function fn({ start, success, fail }) {
return new Promise((resolve, reject) => {
try {
const result = start();
resolve(result);
} catch (error) {
reject(error);
}
})
.then(success)
.catch(fail);
}
// 使用示例
fn({
start: () => 'Start Function',
success: result => console.log('Success:', result),
fail: error => console.error('Error:', error),
});
21. 一个有序的数组,给定一个目标值,找到两个数组中的元素相加为目标值。要求:一次循环
function findTwoSum(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left < right) {
const sum = nums[left] + nums[right];
if (sum === target) {
return [left, right];
} else if (sum < target) {
left++;
} else { // sum > target
right--;
}
}
return [-1, -1]; // 没有找到答案
}
// 测试用例:
console.log(findTwoSum([2, 7, 11, 15], 9)); // 输出:[0, 1]
function findTwoSum(nums, target) {
const map = {};
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map[complement] !== undefined) {
return [map[complement], i];
}
map[nums[i]] = i;
}
return [-1, -1]; // 没有找到答案
}
// 测试用例:
console.log(findTwoSum([3, 2, 4], 6)); // 输出:[1, 2]
22. 求树的深度,先写一个树的结构
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
function maxDepth(root) {
if (root === null) {
return 0;
} else {
let leftHeight = maxDepth(root.left);
let rightHeight = maxDepth(root.right);
return Math.max(leftHeight, rightHeight) + 1;
}
}
23. 最长不重复字符串
function lengthOfLongestSubstring(s) {
let map = new Map()
let l = 0
let max = 0
for(let r=0; r<s.length; r++){
let item = s[r]
if(map.has(item) && map.get(item) >= l){
const index = map.get(item)
l = index + 1
}
max = Math.max(max, r - l + 1)
map.set(item, r)
}
return max
}
// 测试用例:
console.log(lengthOfLongestSubstring("abcabcbb")); // 输出:3 ("abc" 是最长子串)
function lengthOfLongestSubstring(s){
let arr = []
let max = 0
for(let i=0; i<s.length; i++){
let item = s[i]
let index = arr.indexOf(item)
if(index>-1){
arr.splice(0, index+1)
}
arr.push(item)
max = Math.max(max, arr.length)
}
return max
}
24. 二分查找
function search(nums, target){
let l = 0, r = nums.length -1
while(l <= r){
let mid = Math.floor((r-l)/2) + l
let midNum = nums[mid]
if(midNum===target){
return mid
}else if(midNum > target){
r = mid-1
}else if(midNum < target){
l = mid+1
}
}
return -1
}
25. lodash 的 set 和 get
let obj = {
a: {
b: {
c: 'hello'
}
}
}
function set(obj, path, value){
let keys = path.split('.')
let curObj = obj
for(let i=0; i<keys.length-1; i++){
if(!(keys[i] in curObj)){
curObj[keys[i]] = {}
}
curObj = curObj[keys[i]]
}
curObj[keys[keys.length-1]] = value
}
function get(obj, path){
let keys = path.split('.')
let curObj = obj
for(let i=0; i<keys.length; i++){
let key = keys[i]
if(typeof key !== 'object' || !(key in curObj)) {
return undefined
}
curObj = curobj[key]
}
return curObj
}
26. 去除字符串中出现次数最少的字符,不改变顺序
"ababac" => "ababa"
"aaabbbcceeff" => "aaabbb"
function deleteLeast(str){
let map = {}
for(let i=0; i<str.length; i++){
let item = str[i]
if(map[item]){
map[item]++
}else{
map[item] = 1
}
}
let min = Math.min(...Object.values(map))
for(let key in map){
if(map[key]===min){
delete map[key]
}
}
let res = ''
for(let i=0; i<str.length; i++){
let item = str[i]
if(map[item]){
res += item
}
}
return res
}
27. 计算数组中时间的平均时间
const arr = ['8:15', '6:35', '11:22']
function averageTime(arr){
const totalMinutes = arr.reduce((pre, cur)=>{
const [hour, minutes] = cur.split(':')
return pre + Number(hour) * 60 + Number(minutes)
})
let averageMinutes = Math.floor(totalMinutes/arr.length)
const averageHour = Math.floor(averageMinutes/60)
averageMinutes = averageMinutes % 60
averageMinutes = averageMinutes<10 ? '0'+averageMinutes : averageMinutes
return averageHour + ':' + averageMinutes
}
28. 间隔执行函数
function createRepeat(fn, repeat, interval){
let count = 0
return (param) => {
const timer = setInterval(()=>{
fn(param)
count++
if(count>=repaet){
clearInterval(timer)
}
}, interval * 1000)
}
}
29. 不定长二维数组的全排列
const arr = [[A, B], [a, b], [1, 2]]
// [Aa1, Aa2, Ab1, Ab2, .....]
// 动态规划
function permutate(arr){
let res = arr[0].slice()
for(let i=1; i<arr.length; i++){
let pre = res.slice()
res = []
pre.forEach(item=>{
arr[i].forEach(cur=>{
res.push(item+cur)
})
})
}
return res
}
30. 两个字符串对比,得出结论都做了什么操作?插入什么?删除什么?
pre = 'abcde123'
cur = '1abc123'
function diffAction(pre, cur){
}
31. 从数组中,获取最小正数的索引值
function findMinIndex(arr){
let min = Math.max(...arr)
let index = -1
for(let i=0; i<arr.length; i++){
if(arr[i]>=0 && arr[i]<min){
min = arr[i]
index = i
}
}
return index
}
32. 实现一个等待函数,支持让 async 函数在执行时暂停一段时间,函数的入参为暂停的时间
function wait(time){
return new Promise(resolve=> setTimeout(()=>resolve()), time)
}
async function run(){
console.log('start')
await wait(2000)
console.log('end')
}
33. 使用正则,筛选出数组中只包含大小写字母的字符串,并将结果转大写
function filterArr(arr){
arr = arr.filter(item => {
return /^[A-Za-z]+$/.test(item)
})
return arr.map(item => item.toUpperCase())
}
34. 原始的扁平对象转换为如下的非扁平对象
let obj = {
'a.b.c.d': 1
};
let result = {};
for (let key in obj) {
let keys = key.split('.');
let temp = result;
for (let i = 0; i < keys.length - 1; i++) {
temp[keys[i]] = temp[keys[i]] || {};
temp = temp[keys[i]];
}
temp[keys[keys.length - 1]] = obj[key];
}
console.log(result);
35. js 实现数组去重
输入 const arr = ['null', null, null, undefined, {}, { name: 'ImeanAi' }, { name: 'ImeanAi' }, { name: undefined }, {}]
;
输出 const result = ['null', null, undefined, { name: 'ImeanAi' }, { name: undefined }, {}]
结果
const arr = ['null', null, null, undefined, {}, { name: 'ImeanAi' }, { name: 'ImeanAi' }, { name: undefined }, {}];
function compareObjects(obj1, obj2) {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
keys1.sort();
keys2.sort();
return keys1.every((key, index) => {
if (typeof obj1[key] === 'object' && obj1[key] !== null) {
return compareObjects(obj1[key], obj2[key]);
}
return obj1[key] === obj2[key];
});
}
const uniqueArr = arr.filter((item, index) => {
if (typeof item === 'object' && item !== null) {
return (
index === arr.findIndex(obj => {
if (typeof obj === 'object' && obj !== null) {
return compareObjects(obj, item);
}
return false;
})
);
} else {
return arr.indexOf(item) === index;
}
});
console.log(uniqueArr);