数据结构、算法

83 阅读3分钟

1、算法三大思维:贪心(二叉树找左)、二分、动态规划(大问题拆分成小问题,逐级向下分解,用递归思路分析,用循环来实现) 2、凡有序必二分,优化嵌套循环可以考虑双指针 // 把一个数组旋转k步 // 输入[1, 2, 3, 4, 5, 6, 7, 9], 3 // 输出[6, 7, 9,1, 2, 3, 4, 5 ] function rotating(arr, num) { return arr.slice(-num).concat(arr.slice(0, arr.length - num)) } function _rotating1(arr,num) { const spet = Math.abs(num % arr.length) for (let i = 0;i < spet;i++){ const n = arr.pop() if(n){ arr.unshift(n) } } return arr }

function _rotating2(arr,num) {

let arr2 = arr.slice(- num) for (let inx = arr.length - num - 1;inx >= 0;inx--) { arr[inx + num] = arr[inx] } for (let index = 0; index < num; index++) { arr[index]=arr2[index]

} return arr }

image.png // 判断字符串是否括号匹配 function isMatch(left,right) { if(left==='{'&&right==='}')return true if(left==='['&&right===']')return true if(left==='('&&right===')')return true return false } function matchBracket(str) { let stack = [] const leftSymbols = '({[' const rightSymbols = ')}]' for (let i = 0; i < str.length ; i++) { if(leftSymbols.includes(str[i])){ stack.push(str[i]) }else if(rightSymbols.includes(str[i])){ if(isMatch(stack[stack.length-1],str[i])){ stack.pop() }else{ return false } } } return stack.length===0 } console.log(matchBracket('{{()}}')); // 数组转链表 let arr = [100, 200, 300, 400, 500, 600] function anArrayOfLinkedList(arr) { let length = arr.length let curNode = {value:arr[length - 1]} for (let inx = length - 2;inx >= 0;inx--) { curNode = { value: arr[inx], next: curNode }

} return curNode }

// 链表翻转 function listToFlip(obj) { let prevNode = undefined let cruNode = undefined let nextNode = obj while (nextNode) { if (!prevNode && cruNode) { delete cruNode.next } if (cruNode && prevNode) { cruNode.next = prevNode } prevNode = cruNode cruNode = nextNode nextNode = nextNode.next } cruNode.next = prevNode console.log( cruNode); return cruNode }

// 链表实现队列 class TheQueue { head = null tail = null len = 0 add(n) { const newNode = { value: n, next: null } if (this.head == null) { this.head = newNode } const tailNode = this.tail if (tailNode) { tailNode.next = newNode } this.tail = newNode } del() { const headNode = this.head this.head = headNode.next return headNode.value } } let theQueue = new TheQueue() // 二分查找 function binarySearch(arr, target) { let startIndex = 0 let endIndex = arr.length while (startIndex < endIndex) { console.log(startIndex , endIndex); const midindex = Math.floor((startIndex + endIndex)/2) const midvalue = arr[midindex] if(midvalue>target){ endIndex = midindex }else if(midvalue<target){ startIndex = midindex }else{ return midindex } } return -1 } // 找出数组中两个和为n的数 function findTowNumbers(arr, n) { let len = arr.length - 1 let start = 0, end = len while (start < end) { let num = arr[start] + arr[end] if (num > n) { end -= 1 } else if (num < n) { start += 1 } else { return [arr[start],arr[end]] } } } // 二叉树的遍历 // 前序遍历 function theFormerSequenceTraversal(obj) { if (obj === null) { return } console.log(obj.value); theFormerSequenceTraversal(obj.left) theFormerSequenceTraversal(obj.right) } // 中序遍历 function inTheSequenceTraversal(obj) { if (obj === null) { return } inTheSequenceTraversal(obj.left) console.log(obj.value); inTheSequenceTraversal(obj.right) } // 后序遍历 function afterTheSequenceTraversal(obj) { if (obj === null) { return } afterTheSequenceTraversal(obj.left) afterTheSequenceTraversal(obj.right) console.log(obj.value); } // 斐波那契数列// 0112358 function theFibonacciSequence(num) { if(num<2)return num return theFibonacciSequence(num-1)+theFibonacciSequence(num-2) } function theFibonacciSequence2(num) { let n1=1 let n2=0 let res=0 for (let inx = 1; inx < num; inx++) { res=n1+n2 n2=n1 n1=res

} return res } function fibonacci(num) { let sum = 0 let stack = [] for (let i = 0; i < num; i++) { if(i<2){ stack.push(i) }else{ let sum1=stack.pop() let sum2=stack.pop() sum = 1sum1+1sum2 stack.push(sum2,sum1,sum) }

} return stack } // 青蛙跳n级台阶有几种跳法 function theSteps(num) { if(num===1){ return 1 }else if(num===2){ return 2 }else{ return theSteps(num-1)+theSteps(num-2) } } //移动0到末尾 1020030110改为1231100000 // 1、0和非0分到两个数组再合并,2、如下双指针 function moveZero(arr) { let j = -1, len = arr.length for (let i = 0;i < len;i++) { if (arr[i] === 0) { if(j<0) j = i } else if (j >= 0) { const num = arr[i] arr[i] = 0 arr[j] = num j++ } } }

// 字符串中连续最多的字符 // 1、循环嵌套加跳步,2、双指针 function forTheMost(arr) { let len = arr.length, num = 0, char = '', bnum = 0, bchar = '' for (let inx = 0;inx < len - 1;inx++) { if (char === '') char = arr[inx], num = 1 // console.log(arr[inx] === char); if (arr[inx] === char) { num += 1 } else { if (bnum < num) { bnum = num, bchar = char } char = arr[inx]; num = 1 }

} return { bchar, bnum }

} function forTheMost2(str) { let obj = { value: '', num: 0 } for (let i = 0;i < str.length;i++) { let num = 0 const e = str[i]; for (let j = i;j < str.length;j++) { const e2 = str[j]; if (e === e2) { ++num } else { if (obj.num < num) { obj.value = str[i] obj.num = num } else { i = j-1 num = 0 } break }

}

} return obj } // 排序 function theSorting(arr) { let len = arr.length if (len === 0) return arr

let midindex = Math.floor(len / 2) let midvalue = arr.splice(midindex, 1)[0] let left = [] let right = [] for (let i = 0;i < arr.length;i++) { const n = arr[i] if (n < midvalue) { left.push(n) } else { right.push(n) } } return theSorting(left).concat([midvalue], theSorting(right)) }

// 获取对称数(回文数)1、如下翻转比较 2、数字收尾比较(栈)3、数字翻转(取余乘十,剩下的数再取余乘十,直到数小于0 )比较

/* / function numberOfSymmetry(num) { let arr = [] for (let i = 0;i < num;i++) { const s = i.toString() if (s === s.split("").reverse().join('')) { arr.push(i) } } return arr } function numberOfSymmetry2(num) { let arr = [] for (let i = 0;i < num;i++) { const s = i.toString() let flag = true, startIndex = 0, endIndex = s.length - 1 while (startIndex < endIndex) { if (s[startIndex] === s[endIndex]) { ++startIndex, --endIndex } else { flag = false break } } if (flag) { arr.push(i) } } return arr } function numberOfSymmetry3(num) { let arr = [] for (let i = 0;i < num;i++) { let num=i let total = 0 while (num > 0) { total =total10+ num % 10 num = Math.floor(num / 10) } if(total===i){ arr.push(i) } } return arr } // 千分位格式化 1234567转为 1,234,567

function micrometerLevel(num) { let str = '' while (num >= 1000) { let num2 = num % 1000 if (num2 < 100 && num2 >= 10) { str = ',0' + num2 + str } else if (num2 < 10) { str = ',00' + num2 + str } else { str = ',' + num2 + str } num = Math.floor(num / 1000) } return num + str }

function micrometerLevel2(num) { arr = Math.floor(num).toString().split('').reverse() return arr.reduce((prev, val, index) => { if (index % 3 === 0) { if (prev) { return val + ',' + prev } else { return val }

} else {
  return val + prev
}

}, '') } function micrometerLevel3(num) { let res = '' let str = Math.floor(num).toString() for (let i = str.length - 1;i >= 0;i--) { if (i % 3 === 0) { res = str[i] + res if (i !== 0) { res = ',' +res } } else { res = str[i] + res } } return res }

// 切换字母大小写 65-90 97-122 大小写差32 function switchTheLetterCase(str) { let res = '' for (let i = 0;i < str.length;i++) { const num= str.charCodeAt(i) if(num>=65&&num<=90){ res+=String.fromCharCode(num+32) }else if(num>=97&&num<=122){ res+=String.fromCharCode(num-32) }else{ res +=str[i] } } return res } // 扁平化 function recursive(arr) { let res = [] for (let i = 0; i < arr.length; i++) { if(Array.isArray(arr[i])){ let arrs=recursive(arr[i]) arrs.forEach(v => { res.push(v) }); }else{ res.push(arr[i]) }
} return res } function flat(arr,arrr=[]) { arr.forEach(item => { if (Array.isArray(item)) { return fn16(item,arrr) } else { arrr.push(item) } }); return arrr }

// 数组转为树 function anArrayIntoATree(arr) { // 用于 id 和 treeNode 的映射 const idToTreeNode = new Map() let root = null arr.forEach(item => { const { id, name, parentId } = item // 定义 tree node 并加入 map const treeNode = { id, name } idToTreeNode.set(id, treeNode) // 找到 parentNode 并加入到它的 children const parentNode = idToTreeNode.get(parentId) if (parentNode) { if (parentNode.children == null) parentNode.children = [] parentNode.children.push(treeNode) } // 找到根节点 if (parentId === 0) root = treeNode }) return root }

//树转数组 广度优先遍历,用队列 如果深度优先遍历用栈 function treesTurnArray(obj) { let arr = [] let maps = new Map() let queue = [] queue.push(obj) while (queue.length > 0) { let curNode = queue.shift() let { id, name, children } = curNode const parentNode = maps.get(curNode) const parentId = parentNode && parentNode.id || 0 arr.push({ id, name, parentId: parentId || 0 }) if (children) { children.forEach(child => { maps.set(child, curNode) queue.push(child) })

}

} return arr } // 等待+链式调用(把函数放到队列中,不是立即执行) class LazyMan { name = '' tasks = [] // 任务列表 constructor(name) { this.name = name setTimeout(() => { this.next() }) } next() { const task = this.tasks.shift() // 取出当前 tasks 的第一个任务 if (task) task() } eat(food) { const task = () => { console.info(${this.name} eat ${food}) this.next() // 立刻执行下一个任务 } this.tasks.push(task) return this // 链式调用 } sleep(seconds) { const task = () => { console.info(${this.name} 开始睡觉) setTimeout(() => { console.info(${this.name} 已经睡完了 ${seconds}s,开始执行下一个任务) this.next() // xx 秒之后再执行下一个任务 }, seconds * 1000) } this.tasks.push(task) return this // 链式调用 } } // 柯里化函数 function curry(fn) { const fnArgsLength = fn.length // 传入函数的参数长度 let args = []

function calc(...newArgs) { // 积累参数 args = [ ...args, ...newArgs ] if (args.length < fnArgsLength) { // 参数不够,返回函数 return calc } else { // 参数够了,返回执行结果 return fn.apply(this, args.slice(0, fnArgsLength)) } }

return calc } function add(a, b, c) { return a + b + c } // add(10, 20, 30) // 60 const curryAdd = curry(add) const res = curryAdd(10)(20)(30) // 60 image.png