刷剑指offer 4

136 阅读3分钟

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)