1.剑指 Offer 25. 合并两个排序的链表
简单题,合并两个有序链表
var mergeTwoLists = function(l1, l2) {
const prehead = new ListNode(-1)
let prev = prehead
while(l1 || l2) {
if(!l1) {
return l2
}
else if(!l2) {
return l1
} else if(l1.val < l2.val) {
prev.next = l1
} else {
prev.next = l2
}
}
};
2.剑指 Offer 26. 树的子结构
树的问题很多都是用的递归,关键是找到终止条件,找到每层干了什么。
var isSubStructure = function (A, B) {
const isSameTree = (A, B) => {
if (B == null) return true;
if (A == null || A.val != B.val) return false;
return isSameTree(A.left, B.left) && isSameTree(A.right, B.right);
};
if (!A || !B) return false;
return (
isSameTree(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B)
);
};
3.剑指 Offer 27. 二叉树的镜像
递归遍历
var mirrorTree = function(root) {
if(root === null) return null
const left = mirrorTree(root.left)
const right = mirrorTree(root.right)
root.left = right
root.right = left
return root
};
4.剑指 Offer 28. 对称的二叉树
输入: root = [1,2,2,3,4,4,3]
输出: true
如果他只有根节点的话,那他就是对称的。
if(!left && !right) return true
如果他只有左子树或者右子树其中之一的话,那么他就是不对称的。
if(!left || !right) reutrn false
如果左子树根节点的值不等于右子树根节点的值,说明不是对称的。
if(left.val !== right.val) return false
每次把左子树和右子树分别递归
var isSymmetric = function(root) {
if(!root) return true
const dfs = (left,right) => {
if(!left && !right) return true
if(!left || !right) return false
if(left.val !== right.val) return false
return dfs(left.left,right.right) && dfs(left.right, right.left)
}
return dfs(root.left,root.right)
};
5.1每日一题1305. 两棵二叉搜索树中的所有元素
给你 root1 和 root2 这两棵二叉搜索树。请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。
输入: root1 = [2,1,4], root2 = [1,0,3]
输出: [0,1,1,2,3,4]
看到这个题,脑子里第一想法是遍历之后排序,发现可以,时间复杂度O(m+n)递归遍历两棵树。
var getAllElements = function(root1, root2) {
//树,递归
let res = []
function dfs(root) {
if(!root) return
dfs(root.left)
res.push(root.val)
dfs(root.right)
}
dfs(root1)
dfs(root2)
return res.sort((a,b)=> a-b)
};
三叶刷题班第1题416. 分割等和子集
这是一道0-1背包问题,01背包就是每件东西只有一件的背包问题。当意识到是一个01背包问题之后,就开始直接尝试去套用01背包的状态转移方程。根据《算法图解》里的背包偷东西模型,要么选择上一行中的价值,要么选择当前新增行物品中的价值+剩余空间的最大价值
(cell[i][j] = max(cell[i-1][j], num[i][j]+cell[i-1][j-nums[i]]))
var canPartition = function(nums) {
let sum = 0
for(let i=0; i<nums.length;i++) {
sum += nums[i]
}
let target = sum/2 //拆成两个相等的背包,要做的事是填满这两个背包
//如果不能拆成两个,就代表肯定不能拆成两个背包
if(target % 1 !== 0) return false
let price = new Array(nums.length).fill(0).map(()=> new Array(target+1).fill(0))
//处理第一件物品
for(let i=0; i<=target;i++) {
price[0][i] = i >= nums[0] ? nums[0] : 0
}
for(let i=1; i<nums.length; i++) {
let t = nums[i]
for(let j=0; j<=target; j++) {
let no = price[i-1][j]
let yes = j>= t ? price[i-1][j-t] + t : 0
price[i][j] = Math.max(no, yes)
}
}
return price[nums.length-1][target] === target
};
三叶刷题班第2题1049. 最后一块石头的重量 II
输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
一道0-1背包问题(可拿物品有限),把物品价值总和设为sum,然后分成两个背包sum/2,要做的是找到一个 背包最大值(最接近sum/2)