每日打卡算法题
两数之和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
var twoSum = function(nums, target) { let obj = {} for(let i =0; i<nums.length; i++) { let num = nums[i]; if(num in obj) { return [obj[num], i] } else { obj[target - num] = i } } };
|
利用空间换取时间
有效的括号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
var isValid = function(s) { const stack = [] const map = { '(': ')', '{': '}', '[': ']' } for(let i=0;i<s.length;i++) { if(s[i] in map) { stack.push(s[i]) } else { if(map[stack.pop()] !== s[i]) { return false } } } return !stack.length };
|
利用字典的思想
简化路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
var simplifyPath = function(path) { const stack = [] const paths = path.split('/') for(let i =0;i<paths.length;i++) { const p = paths[i] if(p === '..') { stack.pop() } else if(p && p !== '.') { stack.push(p) } } return '/' + stack.join('/') };
|
一个简单的链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| class Node { constructor(element) { this.element = element this.next =null } }
class LinkNodeList { constructor() { this.head = null this.length = 0 }
append(element) { let node = new Node(element) let cur if(!this.head) { this.head = node } else { cur = this.head while(cur.next) { cur = cur.next } cur.next =node } this.length += 1 }
print() { let cur = this.head let ret = [] while(cur) { ret.push(cur.element) cur = cur.next } return ret.join('==>') }
removeAt(index) { let prev let cur = this.head let i = 0 if(index === 0) { this.head = cur.next } else { while(i < index) { prev = cur cur = cur.next i++ } prev.next = cur.next cur.next = null } this.length -= 1; return cur.element; } }
const linkList = new LinkNodeList() linkList.append('hah') linkList.append('yy') linkList.removeAt(1) linkList.print()
|
链表的中间节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
var middleNode = function(head) { let slow = head let fast = head while(fast && fast.next) { slow = slow.next fast = fast.next.next } return slow };
|
没有写边界判断的逻辑,只是一个简单的熟悉链表结构的demo
链表的删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
var removeElements = function(head, val) { let prev = { next: head } let cur = prev
while(cur.next) { if(cur.next.val === val) { cur.next = cur.next.next } else { cur = cur.next } } return prev.next };
|
链表翻转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
var reverseList = function(head) { let cur = head let prev = null while(cur !== null) { let next = cur.next cur.next = prev prev = cur cur = next } return prev };
|
环形链表II
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
var detectCycle = function(head) { let fast = head let slow = head let start = head while(fast && fast.next) { fast = fast.next.next slow = slow.next if(slow == fast) { while(slow && start) { if(slow == start) { return slow } slow = slow.next start = start.next } } } return null };
|
翻转二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
var invertTree = function(root) { if(root == null) { return root } [root.left, root.right] = [invertTree(root.right), invertTree(root.left)]
return root };
|
二叉树遍历
前序遍历:自己-》left-》right
中序遍历:left-》自己-》right
后序遍历:left-》right-》自己
前序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
var preorderTraversal = function(root, arr = []) { let result = [] let stack = [] let cur = root
while(cur || stack.length > 0) { while(cur) { result.push(cur.val) stack.push(cur) cur = cur.left } cur = stack.pop() cur = cur.right }
return result };
|
二叉搜索树:节点自身大于左子树,小于右子树
中序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var inorderTraversal = function(root) { let result = [] let stack = [] let cur = root while(cur || stack.length > 0) { while(cur) { stack.push(cur) cur = cur.left } cur = stack.pop() result.push(cur.val) cur = cur.right } return result };
|
二叉树的深度
1 2 3 4 5 6 7 8 9 10 11 12
|
var maxDepth = function(root) { if(root == null) { return 0 } return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1 };
|
二叉搜索树的最近公共祖先
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var lowestCommonAncestor = function(root, p, q) { while(root) { if(p.val > root.val && q.val > root.val) { root = root.right } else if(q.val < root.val && p.val < root.val) { root = root.left } else { return root } } };
|
二叉树最近公共祖先
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
var lowestCommonAncestor = function(root, p, q) { if(root == null || root == p || root == q) { return root }
let left = lowestCommonAncestor(root.left, p, q) let right = lowestCommonAncestor(root.right, p, q)
if(left == null) { return right } if(right == null) { return left } return root };
|
二分法查找
- 二分法依赖顺序表结构
- 二分法查找针对的是有序数据
- 数据量太大、太小不适合二分法
四种常见的二分法变形问题:
- 查找第一个值等于给定值的元素
- 查找最后一个值等于给定值的元素
- 查找第一个大于等于给定值的元素
- 查找最后一个小于等于给定值的元素