算法细节系列(16):深度优先搜索

详细代码可以fork下Github上leetcode项目,不定期更新。

题目均摘自leetcode:
1. 329 Longest Increasing Path in a Matrix
2. 488 Zuma Game
3. 417 Pacific Atlantic Water Flow
4. 332 Reconstruct Itinerary

329 Longest Increasing Path in a Matrix

Problem:

Given an integer matrix, find the length of the longest increasing path.

From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed).

Example 1:

nums = [
[9,9,4],
[6,6,8],
[2,1,1]
]
Return 4
The longest increasing path is [1,2,6,9]

Example 2:

nums = [
[3,4,5],
[3,2,6],
[2,2,1]
]
Return 4
The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.

求图中不断递增的最大路径长度,采用DFS暴力搜索,代码如下:

public int longestIncreasingPath(int[][] matrix) {row = matrix.length;if (row == 0) return 0;col = matrix[0].length;if (col == 0) return 0;max = 0;for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {count = 1;dfs(matrix,i,j);}}return max;}static int count = 1;static int max = 0;static int row,col;static final int[][] direction = {{-1,0},{1,0},{0,-1},{0,1}};private void dfs(int[][] matrix, int cx, int cy){for (int i = 0; i < 4; i++){int nx = cx + direction[i][0];int ny = cy + direction[i][1];max = Math.max(max, count);if (nx >= 0 && nx < row && ny >=0 && ny < col && matrix[nx][ny] > matrix[cx][cy]){count++;dfs(matrix, nx, ny);//注意状态还原count--;}}}

代码TLE了,原因很简单,该代码没有记录已经搜索完毕的路径长度,而我们知道,从一个起点出发或许能够抵达某个已经搜过的路径上,所以优化代码如下:

public int longestIncreasingPath(int[][] matrix) {int row = matrix.length;if (row == 0) return 0;int col = matrix[0].length;if (col == 0) return 0;int[][] cache = new int[row][col];int max = 1;for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {int len = dfs(matrix, i, j, row, col, cache);max = Math.max(len, max);}}return max;}final static int[][] direction = {{-1,0},{1,0},{0,-1},{0,1}};private int dfs(int[][] matrix, int i , int j, int row, int col, int[][] cache){if (cache[i][j] != 0) return cache[i][j];int max = 1;for (int[] dir : direction){int nx = i + dir[0], ny = j + dir[1];if (nx < 0 || nx >= row || ny < 0 || ny >= col || matrix[nx][ny] <= matrix[i][j]) continue;int len = 1 + dfs(matrix, nx, ny, row, col, cache);max = Math.max(max, len);}return cache[i][j] = max;}

DFS带返回值的特点,天然的能够进行一些状态还原,所以不需要像第一版代码一样,在DFS后加入count--

488 Zuma Game

Problem:

Think about Zuma Game. You have a row of balls on the table, colored red(R), yellow(Y), blue(B), green(G), and white(W). You also have several balls in your hand.

Each time, you may choose a ball in your hand, and insert it into the row (including the leftmost place and rightmost place). Then, if there is a group of 3 or more balls in the same color touching, remove these balls. Keep doing this until no more balls can be removed.

Find the minimal balls you have to insert to remove all the balls on the table. If you cannot remove all the balls, output -1.

Examples:

Input: “WRRBBW”, “RB”
Output: -1
Explanation: WRRBBW -> WRR[R]BBW -> WBBW -> WBB[B]W -> WW

Input: “WWRRBBWW”, “WRBRW”
Output: 2
Explanation: WWRRBBWW -> WWRR[R]BBWW -> WWBBWW -> WWBB[B]WW -> WWWW -> empty

Input:”G”, “GGGGG”
Output: 2
Explanation: G -> G[G] -> GG[G] -> empty

Input: “RBYYBBRRB”, “YRBGB”
Output: 3
Explanation: RBYYBBRRB -> RBYY[Y]BBRRB -> RBBBRRB -> RRRB -> B -> B[B] -> BB[B] -> empty

Note:

  • You may assume that the initial row of balls on the table won’t have any 3 or more consecutive balls with the same color.
  • The number of balls on the table won’t exceed 20, and the string represents these balls is called “board” in the input.
  • The number of balls in your hand won’t exceed 5, and the string represents these balls is called “hand” in the input.
  • Both input strings will be non-empty and only contain characters ‘R’,’Y’,’B’,’G’,’W’.

小时候玩的泡泡龙游戏,遇到三个以上颜色相同的球就消除,直到为空。

思路:
明确搜索对象,此处对象有两个【手中的球】和【桌上的球】,此处以桌上的球为遍历对象,因为我们知道在桌上,出现的球总共就两种情况,每种颜色要么只出现一次,要么只出现连续两次,只要手中的球足以填补成三个,我们就进行消除。遍历所有情况求得一个最小的步数,即为答案。代码如下:

public int findMinStep(String board, String hand) {int[] handCount = new int[32];for (int i = 0; i < hand.length(); i++){handCount[hand.charAt(i)-'A']++; //顺序无关}int min_step = helper(board + "#", handCount);return min_step == 6 ? -1 : min_step;}private int helper(String board, int[] handCount){String s = removeConsecutive(board);if (s.equals("#")) return 0;char[] cc = s.toCharArray();int min_step = 6;for (int i = 0, j = 0; j < s.length(); j++){int step = 0;if (cc[i] == cc[j]) continue;// j - i = 1 or 2int need = 3- (j - i);if (need <= handCount[cc[i]-'A']){step += need;handCount[cc[i]-'A'] -= need;min_step = Math.min(min_step,step + helper(s.substring(0, i) + s.substring(j), handCount));handCount[cc[i]-'A'] += need;}i = j;}return min_step;}private String removeConsecutive(String board) {char[] cc = board.toCharArray();for (int i = 0, j = 0; j < cc.length; j++){if (cc[i] == cc[j]) continue;if (j - i >= 3) return removeConsecutive(board.substring(0, i) + board.substring(j));else i = j;}return board;}

注意一些细节,因为顺序无关,所以我们可以直接用一个map进行计数。防止特殊情况j == s.length(),所以在board后多了一个字符'#'removeConsecutive()该方法针对单独连续的字符串www将返回www而不是空串,需注意。对连续的相同字符串计数的代码可以研究研究,挺不错的一个小技巧。

417 Pacific Atlantic Water Flow

Problem:

Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the “Pacific ocean” touches the left and top edges of the matrix and the “Atlantic ocean” touches the right and bottom edges.

Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.

Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.

Note:

  • The order of returned grid coordinates does not matter.
  • Both m and n are less than 150.

Example:

Given the following 5x5 matrix:

Pacific ~ ~ ~ ~ ~
~ 1 2 2 3 (5) *
~ 3 2 3 (4) (4) *
~ 2 4 (5) 3 1 *
~ (6) (7) 1 4 5 *
~ (5) 1 1 2 4 *
* * * * * Atlantic

Return:

[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).

思路:
可以沿着山峰顺流而下,但得保证每次下降都是流向更低的地方,如果算法不满足,就会出错。在实际编写代码时,发现这种想法较难实现,于是用了一种逆流而上的做法,分别从大西洋和太平洋出发,寻找更高的山峰,只增不减。这样,如果太平洋和大西洋都能抵达某个山峰,该山峰就是我们所求的解。代码如下:

public List<int[]> pacificAtlantic(int[][] matrix) {int row = matrix.length;if (row == 0) return new ArrayList<int[]>();int col = matrix[0].length;if (col == 0) return new ArrayList<int[]>();List<int[]> ans = new ArrayList<>();boolean[][] a = new boolean[row][col];boolean[][] p = new boolean[row][col];for (int i = 0; i < row; i++){dfs(matrix, i, 0, Integer.MIN_VALUE, a);dfs(matrix, i, col-1, Integer.MIN_VALUE, p);}for (int j = 0; j < col; j++){dfs(matrix, 0, j, Integer.MIN_VALUE, a);dfs(matrix, row-1, j, Integer.MIN_VALUE, p);}for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (a[i][j] && p[i][j]){ans.add(new int[]{i,j});}}}return ans;}int[][] dir = {{-1,0},{1,0},{0,-1},{0,1}};private void dfs(int[][] matrix, int i, int j, int height, boolean[][] visited){int row = matrix.length, col = matrix[0].length;if (i < 0 || i >= row || j < 0 || j >= col || matrix[i][j] < height || visited[i][j]){return;}visited[i][j] = true;for (int[] d : dir){dfs(matrix, i+d[0], j+d[1], matrix[i][j], visited);}}

332 Reconstruct Itinerary

Problem:

Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK.

Note:

  • If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string. For example, the itinerary [“JFK”, “LGA”] has a smaller lexical order than [“JFK”, “LGB”].
  • All airports are represented by three capital letters (IATA code).
  • You may assume all tickets form at least one valid itinerary.

Example 1:

tickets = [[“MUC”, “LHR”], [“JFK”, “MUC”], [“SFO”, “SJC”], [“LHR”, “SFO”]]
Return [“JFK”, “MUC”, “LHR”, “SFO”, “SJC”].

Example 2:

tickets = [[“JFK”,”SFO”],[“JFK”,”ATL”],[“SFO”,”ATL”],[“ATL”,”JFK”],[“ATL”,”SFO”]]
Return [“JFK”,”ATL”,”JFK”,”SFO”,”ATL”,”SFO”].
Another possible reconstruction is [“JFK”,”SFO”,”ATL”,”JFK”,”ATL”,”SFO”]. But it is larger in lexical order.

思路:
数据结构采用Map和优先队列来建立邻接矩阵,路径的寻找采用贪心,所以只要DFS而不需要BFS,遍历结束后,从底自上把答案添加到LinkedList中去,算法与数据结构的完美结合,证明暂略。代码如下:

public List<String> findItinerary(String[][] tickets) {Map<String, PriorityQueue<String>> targets = new HashMap<>();for (String[] ticket : tickets)targets.computeIfAbsent(ticket[0], k -> new PriorityQueue<String>()).add(ticket[1]);visit("JFK",targets);return route;}List<String> route = new LinkedList<String>();private void visit(String airport, Map<String, PriorityQueue<String>> targets) {while (targets.containsKey(airport) && !targets.get(airport).isEmpty())visit(targets.get(airport).poll(), targets);route.add(0, airport);}

算法细节系列(16):深度优先搜索相关推荐

  1. 算法初探系列3 -深度优先搜索之剪枝策略

    前言 前两节课蒟蒻君给大家讲解了dfs的基本用法,蒟蒻君来给大家讲一下它的时间复杂度优化~ 铺垫一下 1.搜索树和状态 我们可以根据搜索状态构建一张抽象的图,图上的一个节点就是一个状态,而图上的边就是 ...

  2. 算法细节系列(20):Word Ladder系列

    算法细节系列(20):Word Ladder系列 详细代码可以fork下Github上leetcode项目,不定期更新. 题目摘自leetcode: 1. Leetcode 127: Word Lad ...

  3. 算法细节系列(3):梯度下降法,牛顿法,拟牛顿法

    算法细节系列(3):梯度下降法,牛顿法,拟牛顿法 迭代算法原型 话不多说,直接进入主题.在我看来,不管是梯度下降法还是牛顿法,它们都可以归结为一个式子,即 x=ϕ(x) x = \phi(x) 也就是 ...

  4. 打印数组算法:堆栈与深度优先搜索(迷宫问题)

    每日一贴,今天的内容关键字为打印数组 栈堆的拜访规矩被制约为Push和Pop两种作操,Push(入栈或压栈)向栈顶添加元素,Pop(出栈或弹出)则掏出前当栈顶的元素,也就是说,只能拜访栈顶元素而不能拜 ...

  5. 【从零到蓝桥杯省一】算法详解之深度优先搜索

    前言 大家好,我是泡泡,一名算法爱好者,在学习算法的这条路上有很多的坎坷与'大山',想必各位都深有体会,我认为学习算法的几个很卡的点,首当其冲就是深度优先搜索和广度优先搜索,虽然理解了是什么意思但是完 ...

  6. 优先深度搜索判断曲线相交_程序员必知的十大基础实用算法之-DFS(深度优先搜索)...

    深度优先搜索 深度优先搜索是一种在开发爬虫早期使用较多的方法.它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML文件) .在一个HTML文件中,当一个超链被选择后,被链接的HTML文件 ...

  7. 算法(6)深度优先搜索和广度优先搜索

    一.深度优先搜索(DFS) 主要思路: 从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底,不断递归重复此过程,直到所有的顶点都遍历 ...

  8. 搜索与回溯算法:DFS(深度优先搜索)

    深度优先搜索:1.确定回溯终止条件2.重复生成其他可能 今天开始改用JavaScript 我的LeetCode题解: 力扣,剑指 Offer 12. 矩阵中的路径 力扣,剑指 Offer 13. 机器 ...

  9. 算法初探系列4 - 广度优先搜索之图上搜索

    概述 广度优先搜索,又称宽度优先搜索,简称bfs. 与dfs不同的是,bfs是从根节点开始,先搜索较近的点再搜索较远的点,就像水波扩散一样. 如上图. 此图的dfs序为:A - B - E - F - ...

最新文章

  1. 40 个 SpringBoot 常用注解
  2. 思路+步骤+方法,三步教你如何快速构建用户画像?
  3. 深入FFM原理与实践
  4. 信息学奥赛一本通(1403:素数对)
  5. 【Bringing Old Photos Back to Life】How to train?如何训练
  6. python django前端重构_django修改models重建数据库的操作
  7. android adb server didn't ack
  8. xmlhttp的状态码收集
  9. OS X 使用技巧——在Finder窗口标题栏上显示路径
  10. HDU 5353 Average 贪心
  11. 2、认识常见网络设备
  12. 感谢蜂窝教育,四个月的学习,让我改变了
  13. 2021免费在线客服系统排行
  14. 2018清明假期旅游预测报告:全国游客人次预计破亿
  15. 神马笔记 版本1.3.0
  16. css使背景图片旋转
  17. [JavaScript学习记录] 首次运用于网页,做一个简易利息计算器!!!
  18. 请你详细说说类加载流程,类加载机制及自定义类加载器
  19. 反恐精英枪王对决 服务器维护6,反恐精英之枪王对决
  20. 全国外语水平考试(WSK)

热门文章

  1. hadoop start journalnode小坑
  2. # 英语听抄 (英)
  3. 编写高质量代码改善C#程序的157个建议——建议64:为循环增加Tester-Doer模式而不是将try-catch置于循环内...
  4. SpringMVC @RequestBody问题:Unrecognized field , not marked as ignorable
  5. 【OpenCV 例程 300篇】240. OpenCV 中的 Shi-Tomas 角点检测
  6. 03-sketch基本工具使用
  7. matlab 读取脉冲数,已知一段波形,求脉冲个数,用代码实现
  8. 超级计算机控制人的电影,想知道这部电影的名字,讲述通过超级计算机进入人脑.回到过去.其中有个老教授死亡留下一封信给给主角。...
  9. POE——POE供电详解
  10. sql重复数据只取一条记录