102 二叉树的层序遍历(*)
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
/*
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let arr = []
if(!root)return arr
const q = []
q.push(root)
while(q.length!=0){
const currentLevelSize = q.length;
arr.push([])
for(let i = 1;i<=currentLevelSize;i++){
const node = q.shift()
arr[arr.length-1].push(node.val)
if(node.left) q.push(node.left)
if(node.right)q.push(node.right)
}
}
return arr
};
114 二叉树展开为链表(*)
给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。
/**
* @param {TreeNode} root
* @return {void} Do not return anything, modify root in-place instead.
*/
var flatten = function(root) {
const list = []
const stack = []
let node = root
while(node!==null||stack.length){
while(node!=null){
list.push(node)
stack.push(node)
node = node.left
}
node = stack.pop();
node = node .right
}
const size = list.length
for(let i=1;i<size;i++){
const prev = list[i-1],curr=list[i]
prev.left = null
prev.right= curr
}
}
121 买卖股票的最佳时机(*)
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let maxProfit = 0 //最大收益
let minPrice = prices[0] //最小价格
for(let i=1;i<prices.length;i++){
if(prices[i]<minPrice){
minPrice = prices[i]
}else{
maxProfit = Math.max(prices[i]-minPrice,maxProfit)
}
}
return maxProfit
};
122 买卖股票的最佳时机II(*)
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
var len = prices.length
const dp = new Array(len).fill(0).map(v=>new Array(2).fill(0))
dp[0][0] = 0
dp[0][1] = -prices[0]
for(let i=1;i<len;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i])
dp[i][1] = Math.max(dp[i-1][1],de[i-1][0]-prices[i])
}
return dp[len-1][0]
};
146 LRU 缓存(*)
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
/**
* @param {number} capacity 设置容量
*/
var LRUCache = function(capacity) {
this.capacity = capacity
this.queue = new Map()
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if(this.queue.has(key)){
const value = this.queue.get(key)
this.queue.delete(key)
this.queue.set(key,value)
return value
}
return -1
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if(this.queue.has(key)){
this.queue.delete(key)
}
this.queue.set(key,value)
if(this.queue.size>this.capacity){
if(this.queue.size){
this.queue.delete(this.queue.keys().next().value)
}
}
};
236 叉树的最近公共祖先(*)
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
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&&right!=null)return root
//如果发现了目标节点,则继续向上标记为该目标节点
return left==null?right:left
};
面试题 16.17. 连续数列(*)
给定一个整数数组,找出总和最大的连续数列,并返回总和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let pre = 0, maxAns = nums[0]
nums.forEach(x=>{
pre = Math.max(pre+x,x)
maxAns = Math.max(maxAns,pre)
})
return maxAns
};
面试题 17.01. 不用加号的加法(*)
设计一个函数把两个数字相加。不得使用 + 或者其他算术运算符。
示例:
输入: a = 1, b = 1
输出: 2
/**
* @param {number} a
* @param {number} b
* @return {number}
*/
var add = function(a, b) {
while (b != 0) {
const carry = (a & b) << 1;
a = a ^ b;
b = carry;
}
return a;
};
面试题 17.04. 消失的数字
数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
注意:本题相对书上原题稍作改动
示例 1:
输入:[3,0,1]
输出:2
示例 2:
输入:[9,6,4,2,3,5,7,0,1]
输出:8
/**
* @param {number[]} nums
* @return {number}
*/
var missingNumber = function(nums) {
const set = new Set();
const n = nums.length;
for (let i = 0; i < n; i++) {
set.add(nums[i]);
}
let missing = -1;
for (let i = 0; i <= n; i++) {
if (!set.has(i)) {
missing = i;
break;
}
}
return missing;
};
面试题 17.10. 主要元素
数组中占比超过一半的元素称之为主要元素。给你一个 整数 数组,找出其中的主要元素。若没有,返回 -1 。请设计时间复杂度为 O(N) 、空间复杂度为 O(1) 的解决方案。
示例 1:
输入:[1,2,5,9,5,9,5,5,5]
输出:5
示例 2:
输入:[3,2]
输出:-1
示例 3:
输入:[2,2,1,1,1,2,2]
输出:2
答案:
let find = -1;
let count = 0;
for (const num of nums) {
// 若数量为0,找到的元素设置为当前元素
if (count === 0) {
find = num;
}
if (num === find) {
count++;
} else {
count--;
}
}
count = 0;
for (const num of nums) {
if (num === find) {
count++;
}
}
return count * 2 > nums.length ? find : -1;
面试题 61. 扑克牌中的顺子
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
输入: [1,2,3,4,5]
输出: True
示例 2:
输入: [0,0,1,2,5]
输出: True
答案:
let set = new Set();
let max = 0,min = 14;
for(let a of nums){
if(a==0)continue;
max = Math.max(a,max)
min = Math.min(a,min)
if(set.has(a))return false
set.add(a)
}
return max-min<5