• 算法学习 | 回溯算法之深度优先搜索常见题型练习


    目录

    岛屿的最大面积

    电话号码的字母组合 

    二进制手表 

    组合总数 

    活字印刷


    岛屿的最大面积

    题目链接:leetcode-695.岛屿的最大面积

    示例 

    输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]

    输出:6

    题目分析 

    由题意知,在这个二维数组中,有很多陆地,因此维护一个最大面积,一个临时面积,一个标记数组。遍历二维数组的每一个位置,当遇到陆地且该陆地未被标记过时,就进行搜索,搜索的方式为,从该陆地开始,遍历其上下左右,再遍历每个位置的上下左右,直至遇到边界或海洋或该陆地已被标记过为止。 

    1. class Solution {
    2. int ret;
    3. int tmpArea;
    4. public int maxAreaOfIsland(int[][] grid) {
    5. if (grid == null || grid[0].length == 0) {
    6. return 0;
    7. }
    8. int m = grid.length;
    9. int n = grid[0].length;
    10. int[][] book = new int[m][n];
    11. for (int i = 0; i < m; i++) {
    12. for (int j = 0; j < n; j++) {
    13. if (grid[i][j] == 1 && book[i][j] == 0) {
    14. tmpArea = 0;
    15. dfs(grid, book, i, j);
    16. ret = Math.max(ret, tmpArea);
    17. }
    18. }
    19. }
    20. return ret;
    21. }
    22. private void dfs(int[][] grid, int[][] book, int row, int col) {
    23. if (row < 0 || row >= grid.length || col < 0 || col >= grid[0].length || grid[row][col] == 0) {
    24. return ;
    25. }
    26. if (book[row][col] == 1) {
    27. return ;
    28. }
    29. book[row][col] = 1;
    30. tmpArea++;
    31. dfs(grid, book, row + 1, col);
    32. dfs(grid, book, row - 1, col);
    33. dfs(grid, book, row, col + 1);
    34. dfs(grid, book, row, col - 1);
    35. }
    36. }

    电话号码的字母组合 

    题目链接:leetcode-17.电话号码的字母组合

    示例 

    输入:digits = "23"

    输出: ["ad","ae","af","bd","be","bf","cd","ce","cf"]

    题目分析

    根据题意,每个数字表示几个字符,因此,定义一个字符串数组来记录每个数字所代表的几个字符

    String[] mapString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

     维护一个深度和当前的可能的字母组合,当输入的数字长度等于深度时,就将当前的字母组合加入到结果集中,结束该路径并继续向上回溯;根据深度找到当前的数字,再根据这个数字得到该数字所代表的字符,依次遍历每一种可能,直至所有字符遍历结束。

    1. class Solution {
    2. String[] mapString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    3. List ret = new ArrayList<>();
    4. public List letterCombinations(String digits) {
    5. if (digits == null || digits.length() == 0) {
    6. return new ArrayList<>();
    7. }
    8. StringBuilder curStr = new StringBuilder("");
    9. dfs(digits, curStr, 0);
    10. return ret;
    11. }
    12. private void dfs(String digits, StringBuilder curStr, int curDepth) {
    13. if (curDepth == digits.length()) {
    14. ret.add(curStr.toString());
    15. return ;
    16. }
    17. int curIndex = digits.charAt(curDepth) - '0';
    18. String curMap = mapString[curIndex];
    19. for (int i = 0; i < curMap.length(); i++) {
    20. dfs(digits, curStr.append(curMap.charAt(i)), curDepth + 1);
    21. curStr.deleteCharAt(curStr.length() - 1);
    22. }
    23. }
    24. }

    二进制手表 

    题目链接:leetcode-401.二进制手表

    二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。

    给你一个整数 turnedOn ,表示当前亮着的 LED 的数量,返回二进制手表可以表示的所有可能时间。你可以 按任意顺序 返回答案。

    小时不会以零开头:例如,"01:00" 是无效的时间,正确的写法应该是 "1:00" 。

    分钟必须由两位数组成,可能会以零开头:例如,"10:2" 是无效的时间,正确的写法应该是 "10:02" 。

     

     例如

    输入:turnedOn = 1

    输出:["0:01","0:02","0:04","0:08","0:16","0:32","1:00","2:00","4:00","8:00"]

    题目分析

    表示时的有1,2,4,8,表示分的有1,2,4,8,16,32,分别定义两个数组用来存储时的可能数字和分的可能数字。由于题目中要求小时0~11,分钟0~59,因此表示时的灯最多亮三个,表示分的灯最多亮5个,因此给定的数字需在0~8之间。依次从每一个时和分进行深度优先搜索,当分钟和大于59或小时和大于11就返回,当深度达到给定的数字时,拼接时和分将其加入到结果集中。

    1. class Solution {
    2. int[] hours = {1, 2, 4, 8};
    3. int[] minutes = {1, 2, 4, 8, 16, 32};
    4. List ret = new ArrayList<>();
    5. public List readBinaryWatch(int turnedOn) {
    6. if (turnedOn < 0 || turnedOn >= 9) {
    7. return new ArrayList<>();
    8. }
    9. dfs(turnedOn, 0, 0, 0, 0, 0);
    10. return ret;
    11. }
    12. private void dfs(int turnedOn, int hour, int min, int i, int j, int curDepth) {
    13. if (min > 59 || hour > 11) {
    14. return ;
    15. }
    16. if (curDepth == turnedOn) {
    17. StringBuilder cur = new StringBuilder();
    18. cur.append(hour);
    19. if (min < 10) {
    20. cur.append(":0" + min);
    21. } else {
    22. cur.append(":" + min);
    23. }
    24. ret.add(cur.toString());
    25. return ;
    26. }
    27. for (; i < hours.length; i++) {
    28. hour += hours[i];
    29. dfs(turnedOn, hour, min, i + 1, j, curDepth + 1);
    30. hour -= hours[i];
    31. }
    32. for (; j < minutes.length; j++) {
    33. min += minutes[j];
    34. dfs(turnedOn, hour, min, i, j + 1, curDepth + 1);
    35. min -= minutes[j];
    36. }
    37. }
    38. }

    组合总数 

    题目链接:leetcode-39.组合总数

    示例

    输入:candidates = [2,3,6,7], target = 7

    输出:[[2,2,3],[7]]

    题目分析:

    由于同一个数字可以无限制重复被选取,因此每次从上一个位置开始搜索,边界值的设定:当目前的累加值大于给定的值就返回,当累加值等于给定的值就将其加入结果集中。

    1. class Solution {
    2. List> ret = new ArrayList<>();
    3. List curRet = new ArrayList<>();
    4. int curSum;
    5. public List> combinationSum(int[] candidates, int target) {
    6. dfs(candidates, target, 0);
    7. return ret;
    8. }
    9. private void dfs(int[] candidates, int target, int pre) {
    10. if (curSum > target) {
    11. return ;
    12. }
    13. if (curSum == target) {
    14. ret.add(new ArrayList<>(curRet));
    15. return ;
    16. }
    17. for (int i = pre; i < candidates.length; i++) {
    18. if (candidates[i] > target) {
    19. continue;
    20. }
    21. curSum += candidates[i];
    22. curRet.add(candidates[i]);
    23. dfs(candidates, target, i);
    24. curSum -= curRet.get(curRet.size() - 1);
    25. curRet.remove(curRet.size() - 1);
    26. }
    27. }
    28. }

    活字印刷

    题目链接:leetcode-1079.活字印刷

     

    示例

    输入:"AAB"

    输出:8 

    题目分析

     按照题意tiles中每一个位置的字符在组合中只能出现一次,所以可以用一个标记辅助当去组合新的组合时,可以与tiles中的每一个位置组合,但是如果当前位置已经在当前组合中出现过,则跳过 虽然此题中每一个位置的字符在组合中只能出现一次,但是tiles中可能有相同的字符,所以需要考虑重复的组合,使用HashSet可以实现去重

    1. class Solution {
    2. public int numTilePossibilities(String tiles) {
    3. Set ret = new HashSet<>();
    4. List usedIndex = new ArrayList<>();
    5. for (int i = 0; i < tiles.length(); i++) {
    6. usedIndex.add(0);
    7. }
    8. StringBuilder curStr = new StringBuilder("");
    9. dfs(tiles, curStr, usedIndex, ret);
    10. return ret.size();
    11. }
    12. private void dfs(String tiles, StringBuilder curStr, List usedIndex, Set ret) {
    13. if (curStr.length() != 0) {
    14. ret.add(curStr.toString());
    15. }
    16. for (int i = 0; i < tiles.length(); i++) {
    17. if (usedIndex.get(i) == 1) {
    18. continue;
    19. }
    20. usedIndex.set(i, 1);
    21. dfs(tiles, curStr.append(tiles.charAt(i)), usedIndex, ret);
    22. usedIndex.set(i, 0);
    23. curStr.deleteCharAt(curStr.length() - 1);
    24. }
    25. }
    26. }

     

  • 相关阅读:
    执法记录仪如何防抖
    Python量化-如何获取实时股票信息
    基于图的路径搜索技术基础知识
    Windows系统下安装CouchDB3.3.2教程
    【c++百日刷题计划】 ———— DAY4,带你轻松学习算法
    软件设计模式系列之二十——备忘录模式
    【ARL灯塔搭建详细教程】
    3款录屏录制软件,打造专业级视频内容
    【人工智能】xAI——“X宇宙”又增添了一位新成员
    【网络安全】网站被攻击了怎么办?怎么防护DDOS、CC、XSS、ARP等攻击?
  • 原文地址:https://blog.csdn.net/qq_58284486/article/details/128058833