[刷算法]应付面试的算法思路总结

树的算法经典题目

  1. lt96. 不同的二叉搜索树
    给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
    这道题, 是一道非常新颖的题目, 重点在于降维, 把复杂问题化解成简单问题. 另外, 最后的单纯和数量有关, 也是我没有想到的, 这一点, 还表现出了我总结规律, 手写代码时, 很难捋顺比较模糊的地方

    1. 验证二叉搜索树
      给定一个二叉树,判断其是否是一个有效的二叉搜索树。
      这是一个非常简单的考察概念的题目, 中序遍历, 只要正常做题就行了,没啥新颖的地方.

3.给定一个二叉树,检查它是否是镜像对称的
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
这也是一道非常简单的题目, 类似于把一个二叉树反转,这道题有一定的难度, 那就是如果一个节点发现异常了, 其他结点应该终止检测, 所以这里应该与一个全局变量,来检测是否还需要继续. 但是呢, 看了代码, 又发现, 其实根据 False 结合 AND 的短路, 应该就免去设置这个全局变量了, 代码变得更简洁.
有的时候, 可以结合语法,来简化代码.

  1. 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
    这个题也是一个非常经典的考察概念的题目, 中等难度, 其实算简单, 这个题没有什么好说的.

  2. 给定一个二叉树,找出其最大深度。
    二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
    评价: 这个题是简单难度, 其实是最基本不过的考察概念的题目, 没什么好说的.

    1. 从前序与中序遍历序列构造二叉树
      这个题目, 是中等难度的题目, 考察的代码是比较有技术含量的, 层层考察了递归和最小子问题, 以及降维,分析问题, 是一道百做不厌的题目, 非常的经典.

7.114. 二叉树展开为链表
给定一个二叉树,原地将它展开为一个单链表。

例如,给定二叉树

1

/
2 5
/ \
3 4 6
将其展开为:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

评价: 这道题从经典的角度来看, 是一个考察二叉树遍历的题目, 可以分解成子问题, 是一种第一印象的题目, 然后,另一种思路, 通过栈的方式来解决, 也是不错的, 总之, 一句话, 考察二叉树的先序遍历, 就是需要动动脑子, 把思路变成代码, 要会debug, 要会考虑特殊条件.

  1. 给定一个非空二叉树,返回其最大路径和。
    本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。

示例 1:

输入:[1,2,3]

   1
  / \
 2   3

输出:6
给定一个非空二叉树,返回其最大路径和。

本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。

示例 1:

输入:[1,2,3]

   1
  / \
 2   3

输出:6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-maximum-path-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

评价: 这道题, 考虑要全面, 否则着急下手,肯定要出错, 我确实是犯了几个严重的错误, 考虑不全面, 在面试的时候,应该会暴露出严重的问题, 从而影响评价, 所以以后考虑问题要全面, 这确实是一个非常严峻的问题!!! 这道题是值得练手的, 而且我确实还没有做出来, 当然, 这道题本身也是困难难度. 整体来说, 有思路, 但是考虑不全面,这种题是最有技术含量的,因为他能完整的体现一个人的真实水平!!!

9.538 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node
的新值等于原树中大于或等于 node.val 的值之和。 这道题呢, 也是考察树的遍历,终归中举,无非是后序遍历, 而且代码量也是比较的少, 非常的不错.

  1. 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
    你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则 不为 NULL
    的节点将直接作为新二叉树的节点。
    这道题呢, 它其实是有很多操作空间的, 其实, 是需要和面试官商量, 是重新拷贝一棵树呢, 还是修改原来的结构, 总而言之,这个题是一道不错的题目, 虽然本身不难,但是需要一定的抽象思维能力!! 虽然官方是简单, 但是我认为其难度是中等.

    1. 最大子序和
      给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
这个题的难点,在于维持两个变量, 一个存放最终输出结果, 一个存放当前值, 因为历史总是会开倒车, 所以顶点值需要保存.
也可以维护一个数组, 记录在什么位置,当前的最大和, 然后遍历一遍,然后找出来.

  1. 70.假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意: 给定 n 是一个正整数。
评价: 这是一个经典的递归问题, 可以很轻松的分解成更小的子问题, 直到最小子问题为止, 这个题和斐波那契数列完全契合, 堪称递归的经典解法.
那么有没有办法能够把这个问题化解成动态规划问题呢? 也是有办法的, 因为每一个台阶的到达方式, 都有N种, 而取决于前 N-1 和 N-2种, 所以可以化递归为动态规划.

  1. 121.给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
    如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
    注意:你不能在买入股票前卖出股票。
    这个问题, 是一个经典的0,1背包问题, 也就是一个双重选择问题, 这种问题, 可以用递归来做, 但是也有优化的空间. 因为01背包问题, 普通的解法会求出所有的解, 但是我们只要最大的利润即可. 所以我们只保存最大的利润, 这样可以大大压缩空间效率.
    这里有一个限制,就是最多允许一次买卖, 这是需要注意的点, 另外, 买和卖是两个动作, 如果对01背包问题理解深刻, 我们知道,动作引起状态结点的变化, 我们保存状态结点, 这里所谓的状态, 买了,没有买, 卖了,没有卖. 一共有四种, 但是我们可以根据其规律来进行合并, 想一想, 上一天的买了,今天保持不变, 是什么状态呢? 今天又卖了, 又是什么状态呢?
    想一想我们传统的01背包问题, 我们用一颗树来分析.
    举个例子 [7,1,5,3,6,4]
    第一天 买 -7, 不买,0, 卖 , 不卖,
    第二天 买-1 , 不买-7,0, 卖 -7+1=-6 , 不卖 -7

第二天 买-5 , 不买 -1,-7,0,-6, 卖 4,-2, 不卖 -7

说白了, 我们分析的状态,主要是当前的利润, 以及当前的利润所以来的选择. 我知道,有一个坎很难迈过去, 就是状态其实是, 持有还是没有持有.
这里, 需要重点去理解.这里, 很难理解.

  1. 198.你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,
    如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

分析点评: 还是01背包问题, 每次都有两个选择, 偷还是不偷, 然后第二天的计划又是从第一天迁移过去的.
归根结底, 这个题有它的特殊情况. 比如选择今天偷, 那么昨天的一定是不能偷的, 今天偷了,那么得到的金额就是昨天没偷加上今天偷得的金额, 而如果今天不偷, 那么是从两种情况演变而来的, 一种是昨天也没有偷(当前金额就是昨天没偷的), 另一种是昨天偷了(金额就是昨天偷得的)

举个例子, [1,2,3,1]
第一天: 不偷 0 偷 1
第二天: 不偷 0,1 偷:0+2
第三天: 不偷:0,1,2, 偷了: 3,4
第四天: 不偷: 0,1,2,3,4, 偷了: 1,2,3
可见,根据这个分析, 我们可以遍历最后的结果, 找出偷了或者没有偷的最大的结果.

但是,我们可以优化一下, 我们只想很找最大值, 所以我们没有必要, 这样太浪费空间了,我们只用保存头或者不偷的最大值就可以了.
所以,我们借用一个二维数组, 2*n的数组
即可.

15.给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
原网址: https://leetcode-cn.com/problems/edit-distance/
你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符

评价: 这道题, 我们看得出来, 可以用递归来做,因为这个道题, 有化简问题的可能性, 如果两个单词都是1个单词的长度, 而且不相同, 那么就返回1, 如果相同,就返回0. 我们要求的是最小的编辑数量, 因此我们可以在每个位置有三种选择, 插入, 删除,替换.
假设word1 现在指向i, word2 现在指向j
如果 word1[i] == word2[j] , 那么 继续递归 判断 word1[i+1] 和 word2[j+1], 否则的话,我们进行三种操作.

第一种操作, 给word1在i处插入一个字符, 我们继续判断 word1[i]和word2[j+1]是否相等,编辑距离+1, 我们只是假想插入一个, 所以编辑距离加1, 但是实际上我们并有插入, 所以i的位置, 还是保持不变, 这就是我们继续用 word1[i]和word2[j+1] 比较的原因.

第二种操作, 给word1在i处删除一个字符, 我们继续判断 word1[i+1]和word2[j]是否相等,编辑距离+1, 我们只是假想删除一个, 所以编辑距离加1, 但是实际上我们并有插入, 所以i的位置前进1个, j还是保持不变, 这就是我们继续用 word1[i+1]和word2[j] 比较的原因.

第三种操作, 给word1在i处替换一个字符, 我们继续判断 word1[i+1]和word2[j+1]是否相等,编辑距离+1, 我们只是假想替换一个, 所以编辑距离加1, 但是实际上我们并有替换, 所以i的位置前进1个, j的位置也前进1个, 这就是我们继续用 word1[i+1]和word2[j+1] 比较的原因.

我们既然要最小的, 那么我们就需要取三种操作最小的一个. 在递归的时候我们设置边界条件,就可以了.
那么这个题,如果用动态规划该怎么做呢?
和我们的思维相反, 我们根据当前的位置, 从左,上,左上角 三个坐标的值推算出当前的值的大小.
这个其实有待考虑…
其实, 动态规划每个点的值,也是需要反向考虑的…只不过先正向考虑,分析其转换关系. 正向考虑是从理解的角度分析, 反向考虑是从数理的角度单纯分析.

    1. 给定一个 非空 字符串 s 和一个包含 非空 单词的列表 wordDict ,判定 s
      是否可以被空格拆分为一个或多个在字典中出现的单词。

评价: 这个问题呢, 其实我一开始是没有想明白的. 但是不管怎么样, 你能想到的首先应该是朴素的解法, 也就是简单的解法, 第一个想到的,还应该是化解问题, 大问题变小问题. 所以,这是一个递归可以解决的问题, 但是, 因为这里是一个动态规划的问题, 我们自然也应该用动态规划的思路去分析这个问题. 所谓动态规划问题, 就是根据前面的答案去推倒后面的答案.
但是, 怎么用前面的答案去推倒后面的答案呢?
答案是可以的, 先根据前面的. 然后去推倒后面的.
以 “leetcode”, wordDict = [“leet”, “code”] 距离
过程是这样的:
当i=0的时候, 设置dp[0]= True
然后i, 分析 l是不是在字典里, le是不是在, leet是不是在, leetc是不是在, leetco是不是在…
然后从i=1开始分析, 如果dp[1]=True, 继续分析
只要发现 dp[length] = True, 就退出.

  1. 最长递增序列, 这个题是一个熟悉的题, 之前做过, 现在再复习一遍.
    https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-dong-tai-gui-hua-2/
    这里的这个答案可以实现 O(nlogN)

  2. 给定不同面额的硬币 coins 和一个总金额
    amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
    你可以认为每种硬币的数量是无限的
    p评价: 这个题, 和字符串拆解, 简直一个妈生的, 不解释,无脑, 就硬锤就完事了.
    我怎么解释我的思路呢,
    一样的…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值