Leetcode刷题(Week1)——宽(深)度优先遍历专题

刷题时间: 2019/04/04 – 2019/04/07
主播:yxc(闫雪灿)
视频链接: https://www.bilibili.com/video/av32546525?from=search&seid=14001345623296049881

题号题目链接
127Word Ladderhttps://leetcode.com/problems/word-ladder/
131Palindrome Partitioninghttps://leetcode.com/problems/palindrome-partitioning/
77Combinationshttps://leetcode.com/problems/combinations/
52N-Queens IIhttps://leetcode.com/problems/n-queens-ii/
51N-Queenshttps://leetcode.com/problems/n-queens/
79Word Searchhttps://leetcode.com/problems/word-search/
111Minimum Depth of Binary Treehttps://leetcode.com/problems/minimum-depth-of-binary-tree/
279Perfect Squareshttps://leetcode.com/problems/perfect-squares/
733Flood Fillhttps://leetcode.com/problems/flood-fill/submissions/
200Number of Islandshttps://leetcode.com/problems/number-of-islands/
130Surrounded Regionshttps://leetcode.com/problems/surrounded-regions/
543Diameter of Binary Treehttps://leetcode.com/problems/diameter-of-binary-tree/
127Word Ladderhttps://leetcode.com/problems/word-ladder/
54201 Matrixhttps://leetcode.com/problems/01-matrix/
207Course Schedulehttps://leetcode.com/problems/course-schedule/
210Course Schedule IIhttps://leetcode.com/problems/course-schedule-ii/
494Target Sumhttps://leetcode.com/problems/target-sum/
560Subarray Sum Equals Khttps://leetcode.com/problems/subarray-sum-equals-k/
103Binary Tree Zigzag Level Order Traversalhttps://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/
116Populating Next Right Pointers in Each Nodehttps://leetcode.com/problems/populating-next-right-pointers-in-each-node/

解题心得:

No.127 词梯 (AC)

  • 本题求两个词之间的最小转化距离,解题思路:BFS + 哈希表 + 删除词
  • 本题需要将使用过的词从词典中删掉,不然会TLE。可以这样做的依据时, 次当前词结尾的距离已经是最小距离,即使在后面再出现,也是大于当前距离的, 因此,完全可以将它删掉。
  • 哈希表用于记录转换到每一个词的最小转移距离。

No.131 打印一个字符串的所有回文子串的划分方式 (AC)

  • 本题也是典型的深搜问题
  • 一次枚举1~(len - index)长度的子串,先判断它是否为回文子串,若是,则继续dfs。当枚举完整个字符串时,将当前数组加到答案数组中。

No.77 打印符合要求的组合 (AC)

  • 典型深搜问题
  • 需要判断是否达到指定长度,只有达到指定长度才将当前组合放到答案中去;需要判断索引是否越界,若越界,则返回,不用继续递归。

No.52 八皇后问题 (AC)

  • 与下一题基本一致,本题只要记录答案的数量,下一题需要将每一种答案打印出来。

No.51 八皇后问题 (AC)

  • 深搜+回溯
  • 需要记录行,列,和两个对角线是否存在“皇后”

No.79 在一个矩阵中搜索某条路径是否存在 (AC)(划重点)

  • 这样的搜索问题dfs和bfs都可以解决,通常情况下写成dfs,代码会更简洁一点。
  • dfs的时候,要先在矩阵中循环找到和word的第一个字母相同的元素的位置,然后开始dfs,dfs时直接基于当前位置即可,不必再在矩阵中循环。
  • 另外,矩阵中每个字母只能被用一次,因此需要一个矩阵记录某个位置的元素是否被用过。这里还比较特殊的一点是,如果一条路径搜索不成功,需要从另一个可能的入口开始dfs,因此之前被访问的位置要重新被置为未访问过的状态,因此,在写代码时,要注意每一次循环结束之后,及时恢复现场。
  • 这类问题还有一个地方特别容易写出bug,之前在做此类问题时,每次都会写成bug,这里列出来。
bool dfs(vector<vector<char>>& board, string word, int i, int j, int index, vector<vector<bool>>& is_visited){
        // BUG 写法
        // if (index == word.size()) return true;
        // if (board[i][j] != word[index]) return false;
        
        // 正确代码
        if (board[i][j] != word[index]) return false;
        index++;
        if (index == word.size()) return true;
        ...
        return false;
        
    }

以上的bug代码,在处理eg: [["a"]], "a" 的问题时会出现问题,因此判断相等后,及时将index++,若达到结束条件,则搜索成功。

No.111 求数的最小深度(AC)

  • 这里采用宽度优先遍历(BFS)更好,找到最浅的叶子节点即可。
  • 不过有一点疑问: 是不是得搜索整棵树?
  • 边界条件:
  • 为空, 返回0
  • 若根节点只有一个子树,那么这颗树的最浅层决定于该子树,而不是空缺子树的0,空缺子树不存在叶节点。

No.279 求一个数n可以由最少几个“完美数”(1, 4,9, 16,…)求和得到。(TLE–>AC)

  • 采用DP的方式来做(枚举),存在超时的问题

参考yxc的方法(BFS)来做:

  • 仍然按照DP从最后一步往前推的思路来做,代码可以写出来,问题在于怎么表示当前队列中的元素已经被处理过几次。而且队列中同一个元素可能会在不同的地方出现,应该保留被处理最小的记录。
  • 因此换一种思路,从0开始不断往里加数,这样就可以保证转移公式每次的值都是有效的。
  • 同样需要注意的是,对队列中的同一个数要取处理次数最小的次数记录,因此每次在把一个新数放到队列时,要考虑是否更新它的次数。这里慎用min函数,因为cnt[0] = 0,盲目使用会导致结果始终为0,具体处理方式见代码。
  • 这里可以看成是求图中某一个点大0的最短距离

No.733 洪泛(AC)
BFS方法:

  • 用deque来暂时存储需要遍历的位置
  • 需要一个额外的vector二维数组来记录某个格子是否被访问过,已经被访问的不需要再被添加到deque中,否则会造成死循环
  • !!!在循环访问矩阵中的元素时,需要先判断是否越界!!!
  • 什么时候加!(取反)要仔细考虑一下,老容易写反
  • Accepted!

DFS方法:

  • 需要注意的一点是,当更新的颜色和原来的颜色相同时,不做处理,否则会陷入死循环。

No.200 有多少孤岛 (周围都是水,或者已是边界)(AC)
BFS方法:

  • 思路和733基本一致
  • 需要加两层循环,保证每个点都被遍历过
  • 把以一个点(“1”)为中心的所有点(包括“0”)都加到deque对列中,然后按照deque中的点开始扩展,如果是0则不用扩展,如果为1则扩展,扩展的时候已经被访问过的点不再加到deque中,避免死循环。 当deque队列为空时, 形成一个孤岛。然后返回最上层的循环,继续遍历没有访问过的位置。

DFS方法:

  • 遍历一遍,每次遇到字符‘1’之后DFS将与之相邻的‘1’变成2,遍历整个矩阵,遇到的1的个数即为孤岛个数。

No.130 把被严格包围的封闭区域置为和周围一致(AC)
BFS方法:

  • 和前几题思路大致相同,每次把一个联通的区域遍历完。不同的是,需要判断这个联通成分是不是严格的封闭区间,引入一个bool变量记录。如果是封闭变量,在遍历结束之后,将“O”置为“X”。
  • 需要注意的点和前几题类似,在两层循环内,已经访问过的点或者不符合要求的点不做处理
  • 本题中涉及到将封闭区域的“O”置为“X”,所以还需要一个额外的deque对来来存储封闭区域内的点

DFS方法:

  • 可以转变一种思路,首先遍历外围的点,当遇到‘O’是DFS, 并将它与所有与之相邻的置为‘Y’。完成后,重新遍历一遍,将中间全封闭保卫的‘O’置为‘X’,将‘Y’置为‘O’。

No.543 找二叉树中最长的路径(可以不过根节点)(AC)

  • 用深度遍历的方法来做
  • dfs过程中要同时返回子树的深度以及该子树中最长的路径包含的结点数
  • 最终的返回结果(路径段数) = 最大结点数 - 1 。
  • 特殊情况: 当数为空时,若不特判,将返回-1, 与题意不符,应特判为0。

No.127 找出一个单词(strat)能否通过字典中的单词转换成另一个单词(end),且转换过程中每次只能改变单词中的一个字符(WA–>TLE)

  • 需要遍历
  • 代码有Bug
  • 未解决问题在于: 当dog可以同时转换成log和dot时,以什么样的顺序来枚举和存储答案

换一种思路:
本题要求最小,用BFS来做

  • 有几个点需要注意。 1.最终的返回值需不需要+1;2. 比较两个string是否知否一个字符不相同,这里还是容易写错的,一个比较好的模板如下:
bool check(string begin, string end){
        int res = 0;
        for (int i = 0; i < begin.size(); i++) res += begin[i] != end[i];
        return res == 1;
    }

No.542 找到0-1矩阵中每个位置离‘0’的最近距离(AC)

  • 题目的第一个关键点在于用什么样的顺序来遍历整个矩阵。如果直接两层for循环的话,那么可能出现的问题是,用于更新当前点的相关点并没有被更新,那么更新显然无效。为了避免这种情况,可以先找到一个为‘0’的位置,以此点展开,每次更新周围的点,并把没有被遍历过的点增加到deque队列中。这样做可以保证每个点都会被遍历,同时每次点的更新都是基于已被遍历(更新)的点,保证更新的有效性。
  • 还有一点需要想清楚,一个点会是多个点的相邻点,因此会被更新若干次,只需在若干次更新中保留最小的值即可。
  • 原始为0-1矩阵,如果直接用min函数更新点的值,需要讨论本来值为1的情况,比较麻烦。为了避免这个问题,可以在预处理时,将为值为‘1’的位置全部置为INT_MAX,这样就可以直接用min函数进行比较。

No.207 排课表(WA–>AC)

  • 典型的拓扑排序问题
  • 将先修关系构成一张图,由每个数对的第二个数字向第一个数字连边。首先将所有入度为0的点进队,准备拓扑排序。宽搜过程中,将当前结点所关联的结点的入度减1;若发现新的入度为0的结点,则将其进队。最后如果所有结点所有节点都被便历过,则说明可以满足要求;否则,先修关系存在环。
  • 只要存在环,就不满足要求。
  • 下面是拓扑排序常用模板
    在这里插入图片描述
    No.210 排课程表进阶(AC)
  • 把排课顺序输出
  • 用一个辅助vector存储可休课表,如果可修满,则输出,否者输出空。

No.494 求目标和可能的方案数 (AC)

  • 深搜dfs解决

NO. 560 求整数序列可以构成和为K的连续数列的数目 (AC)

  • 典型深搜问题
  • 要注意将参数sum恢复现场

No.103 Z形打印二叉树 (AC)

  • 用双端队列存储二叉树中的结点,每一层结点以Nullptr作为结尾标志
  • 用一个bool变量表示当前是正序打印还是逆序打印,没循环一层,改变其符号
  • 需要特别注意的是,需要对终止条件做判断,即当前队列中只有一个元素,且为nullptr时可以结束循环。判断条件的位置也很重要,需要把最后一行打印出来之后再结束。

No.116 将“完美二叉树”的左结点指向其右结点 (AC)

  • 此题抓住“完美二叉树”的特点,即每一层的结点都有左右两个儿子
  • 用BFS的方法,使前一个结点指向后一个结点即可。
  • 每一层的边界需要特殊考虑;循环结束break条件需要考虑.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值