Depth-first Search深度优先搜索专题4

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/flying_all/article/details/80401215

576. Out of Boundary Paths

思路:这道题目难倒了我。最直接的思路是暴力搜索。要注意的问题1是需要仔细观察Example2,轨迹不同意思是可以从A点到B点,再从B点到A点也可以,只要step够用。所以暴力搜索,在(i,j)点在步骤允许范围内肆意地向4个方向扩散。退出条件是if (i == -1 || j == -1 || i == m || j == n),计数退出。这样会超时。
我知道该用动态规划了,但是找不出动态方程。
动态规划:思路是这样的。例如输入为 m=2,n=3,N=3,i=0,j=1
这里写图片描述
如果走1不就能走出边界的话,按箭头走。count+1。因为(0,1)只有一个方向能走出边界,而且到达(0,1)的路径只有1条。
接下来考虑走2步能走出边界的方法。从上图的位置(0,1)到下图。
这里写图片描述
count需要分别加上:2,2,1。解释如下:
从(0,1)到(0,0)只有一条路径,(0,0)有2个方向走出边界,所以count+2;
从(0,1)到(0,2)有1条路径,(0,2)有2个方向走出边界,所以count+2;
从(0,1)到(1,1)有1条路径,(1,1)有1个方向走出边界,所以count+1。

接下来考虑走3步走出边界的方法。从上图(0,0),(1,1),(0,2) 位置开始到下图。
这里写图片描述
有3条路径可以到达(0,1),count+3;
有2条路径可以达到(0,0),count+2*2;
有2条路径可以达到(1,2),count+2*2。
最终得总数是17。
用数组dp存储到达(i,j)有几条路径。每次迭代新的newDP[i][j] = dp[i−1][j]+dp[i+1][j]+dp[i][j−1]+dp[i][j+1];dp是上一轮的dp。
我没完成dp思路,是因为我想的是dp[i][j]表示有多少通过(i,j)能有多少count方向出去,也就是最后的总数。
代码

210. Course Schedule II

思路:与207. Course Schedule类似,只是记录下排课顺序即可。

332. Reconstruct Itinerary

思路:题目一看,和graph相关,和DFS相关。而且要求返回字母序列小的。构建map,对map的value值排序。一个一个输出即可。可是要注意:所有的tickets是需要用完的。有些情况下先使用顺序小的票,不一定能走完。解决方法:dfs函数返回true,如果能走完的情况。接着遇到了问题2:超时.解决:逻辑写错了。
代码

130. Surrounded Regions

思路:难点是题目理解。我理解的题意是:如果O在矩形最外圈,那么它不会被翻转为X;如果有和最外圈的O在垂直方向上或者水平方向上相邻的O,那它也不会被翻转为X。其余的O被翻转为X。这样的话根本用不到DFS、BFS之类的。
实际题目含义是:所有被X包围的O都翻转为X。
这里写图片描述
图中画红色部分的O就是被X包围的。
这里写图片描述
图中就没有被X完全包围的O。

BFS思路:在矩形边上的O肯定没有被X包围。在垂直、水平方向上与此O相邻的O也是不被包围的。可以先把不被包围的O替换为#。把边界的O 递归处理完成之后,剩余的O就是需要替换的。
Union-Find思路:将O分为两组;一组是与dummyNode一组,不改变值的;其他组是需要改变值的。
代码

98. Validate Binary Search Tree

思路:是否有效二叉检索树。DFS的思路。先判断node是否有效,接着判断node的左节点是否有效,判断node的右节点是否有效。只是注意,有效值是一个区间。
代码

778. Swim in Rising Water

思路:例如输入如下图:
这里写图片描述

t=0
    cost=0
    visited[0][0]=true
    可以选择的 1,24;
    选择1,增加耗时1=(1-0)
t=1
    cost+=1
    visited[0][1]=true;
    可以选择的 2,23
    选择2,增加耗时1=(2-1)
t=2
    cost+=1
    visited[0][2]=true;
    可以选择的 3,22

    ….一直走到(n-1,n-1)

每一步都选择最小的,就一定是最小的吗?不一定,没有理论支持。那就需要把所有路径都走一遍。在走的过程中如果发现耗时已经>目前的最小耗时就返回。

结果:超时。

学习1:超时是因为我还没有看到事物的本质。You can swim infinite distance in zero time。可以在瞬时穿过好多个区块。例如下图中。起点时刻就是10,或者说等到t=10才能开始移动。移动的时候,因为9,1,2,0,7都 < 10 ,所以相当于瞬时可以达到这些地方。那就相当于在图中划线的周围找到下一个 > 10 的最小值就是下一步要走的区块。

这里写图片描述
    可以考虑的思路是用一个优先队列保存点(i,j)的邻接节点,值小的排在前面。不断弹出,不断加入,直到遇到目标节点。原来题目和代码之间的翻译差距是这么大。好神奇!

学习2:在上一个解决方法中能感觉到是可以把小于10的区块合并成一组。接着找11,再把小于11的相邻元素合并成一组。接着找12,再把小于12的相邻元素合并为一组。最终合并到右下角。这里合并的时候要考虑清楚合并的是元素的值,还是下标。因为最后判断条件不同。在代码swimInWaterV3中合并的是下标,所以最后判断0和N*N-1在同一组,即可退出循环。
这种题目理解和代码,这个等价关系也是令人惊叹。hard类型的题目果然不同凡响。

代码

827. Making A Large Island

思路:对于遇到的每个0,尝试修改为1,用dfs数数面积;取最大的面积值.当grid中没有0的时候,面积为n^2。
学习:将0周围的1分组,可以连续在一起的1分为一组算一次面积。最后再将0周围不同组的面积加起来。找到最大值就是面积。
代码

猜你喜欢

转载自blog.csdn.net/flying_all/article/details/80401215