我是靠谱客的博主 迷路菠萝,最近开发中收集的这篇文章主要介绍[java]——leetcode刷题(深度优先搜索)(中等??)(TBC)前言26.526. 优美的排列27.515. 在每个树行中找最大值31. 1110. 删点成林32.547. 省份数量33.947. 移除最多的同行或同列石头34. 337. 打家劫舍 III35. 面试题 16.19. 水域大小36.117. 填充每个节点的下一个右侧节点指针 II37. 638. 大礼包38.1254. 统计封闭岛屿的数目39. 面试题 04.06. 后继者40. 1306. 跳跃游戏 III41.面试,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

  • 前言
  • [26.526. 优美的排列](https://leetcode-cn.com/problems/beautiful-arrangement/)
  • [27.515. 在每个树行中找最大值](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)
  • [31. 1110. 删点成林](https://leetcode-cn.com/problems/delete-nodes-and-return-forest/)
  • [32.547. 省份数量](https://leetcode-cn.com/problems/number-of-provinces/)
  • [33.947. 移除最多的同行或同列石头](https://leetcode-cn.com/problems/most-stones-removed-with-same-row-or-column/)
  • [34. 337. 打家劫舍 III](https://leetcode-cn.com/problems/house-robber-iii/)
  • [35. 面试题 16.19. 水域大小](https://leetcode-cn.com/problems/pond-sizes-lcci/)
  • [36.117. 填充每个节点的下一个右侧节点指针 II](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/)
  • [37. 638. 大礼包](https://leetcode-cn.com/problems/shopping-offers/)
  • [38.1254. 统计封闭岛屿的数目](https://leetcode-cn.com/problems/number-of-closed-islands/)
  • [39. 面试题 04.06. 后继者](https://leetcode-cn.com/problems/successor-lcci/)
  • [40. 1306. 跳跃游戏 III](https://leetcode-cn.com/problems/jump-game-iii/)
  • [41.面试题34. 二叉树中和为某一值的路径](https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/)
  • [42.756. 金字塔转换矩阵](https://leetcode-cn.com/problems/pyramid-transition-matrix/)
  • [43. 17. 电话号码的字母组合](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/)
    • [44.491. 递增子序列](https://leetcode-cn.com/problems/increasing-subsequences/)

前言

我又回来啦~

26.526. 优美的排列

题目描述:

假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:
第 i 位的数字能被 i 整除
i 能被第 i 位上的数字整除
现在给定一个整数 N,请问可以构造多少个优美的排列?

思路:
定义一个n+1长的free数组,记录有哪些数字已经被使用了;cot记录了当前已经包含了多少个数字.在每次dfs开始之前,一定是选中了一个新的数字,需要修改free数组对应位置,以及cot,在每次dfs结束之后,考虑同一位置的不同可能情况,所以需要把原来的修改撤回.
代码:

class Solution {
    int ans = 0;
    int n;
    public int countArrangement(int n) {
        // i 满足, 1 - i-1, i+1, N
        this.n = n;
        int[] free = new int[n+1];
        dfs(free, 0);
        return ans;
    }
    public void dfs(int[] free, int cot){
        if(cot==n){
            ans++;
            return;
        }
        for(int i = 1;i<free.length;i++){
            if(free[i]==0&&check(cot+1, i)){
                free[i] = 1;
                cot ++;
                dfs(free, cot);
                free[i] = 0;
                cot --;
            }
        }
    }
    public boolean check(int idx, int i){
        return idx%i==0 || i%idx==0;
    }
}

官方答案:回来再看

27.515. 在每个树行中找最大值

题目描述:

您需要在二叉树的每一行中找到最大的值。

思路:维护一个ArrayList num_lst,每一次"depth==num_lst.size()",代表了当前的深度最深,否则更新已存在深度的值.

class Solution {
    public List<Integer> num_lst = new ArrayList<Integer>();
    public List<Integer> largestValues(TreeNode root) {
        dfs(root,0);
        return num_lst;
    }
    public void dfs(TreeNode root,int depth){
        if(root==null) return;
        if(depth==num_lst.size()){
            num_lst.add(root.val);
        }else{
            num_lst.set(depth, Math.max(num_lst.get(depth), root.val));
        }
        dfs(root.left, depth+1);
        dfs(root.right, depth+1);
    }
}

中间的28、29、30漏了~

31. 1110. 删点成林

题目描述:

给出二叉树的根节点 root,树上每个节点都有一个不同的值。
如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。
返回森林中的每棵树。你可以按任意顺序组织答案。

思路:
把节点加入答案需要有两个条件:

  • 节点不被删除
  • 节点没有父亲(父亲可能本来就没有(root)或者被删除了)

由于递归的思路,每一个节点既是父亲也是儿子.作为父亲,它需要:1. 判断自己要不要被删除 2. 告诉自己的左右孩子自己的状况(递归) 3. 修改自己和左右孩子的联系(根据递归的结果进行操作) 作为儿子,它需要:1. 结合自己要不要被删除和自己有没有父亲,考虑是否加入答案 2. 告诉自己的父亲自己有没有被删除(递归的结果).

代码:

class Solution {
    Set<Integer> TODELETE; 
    public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {
        TODELETE = Arrays.stream(to_delete).boxed().collect(Collectors.toSet());
        List<TreeNode> ans = new ArrayList<>();
        dfs(root, ans, false);
        return ans;
    }
    public boolean dfs(TreeNode root, List<TreeNode> ans, boolean parentExists){
        //作为父亲
        if(root==null) return false;
        boolean del = TODELETE.contains(root.val);
        if(dfs(root.left, ans, !del)){
            root.left=null;
        }
        if(dfs(root.right, ans, !del)){
            root.right=null;
        }
        //作为儿子
        if(!del&&!parentExists){
            ans.add(root);
        }
        return del;
    }
}

32.547. 省份数量

题目描述:

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。

思路:并查集

代码:

class Solution {
    public int findCircleNum(int[][] isConnected) {
        // 并查集yyds!
        bcg BCG = new bcg(isConnected.length);
        int row = isConnected.length;
        int col = isConnected[0].length;
        for(int i = 1; i < row; i++){
            for(int j = 0; j < i; j++){
                if(isConnected[i][j]==1){
                    BCG.union(i,j);
                }
            }
        }
        return BCG.getcot();
    }
    public class bcg{
        private int cot;
        private int[] parents;
        public bcg(int size){
            cot = size;
            parents = new int[size];
            for(int i=0;i<parents.length;i++){
                parents[i] = i;
            }
        }
        public int findroot(int i){
            if(parents[i]!=i){
                parents[i] = findroot(parents[i]);
            }
            return parents[i];
        }
        public void union(int i, int j){
            int root_i = findroot(i);
            int root_j = findroot(j);
            if(root_i==root_j) return;
            parents[root_i] = root_j;
            cot --;
        }
        public int getcot(){
            return cot;
        }
    }
}

33.947. 移除最多的同行或同列石头

题目描述:

n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。
如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。
给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回 可以移除的石子 的最大数量。

思路1:并查集yyds,可以移除的石头的最大数量=所有的石头数-连通子图数.

代码1:

class Solution {
    public int removeStones(int[][] stones) {
        bcg BCG = new bcg(stones.length);
        for(int i=0;i<stones.length-1;i++){
            for(int j=i+1;j<stones.length;j++){
                int[] preArray = stones[i];
                int[] nowArray = stones[j];
                if(preArray[0]==nowArray[0]||preArray[1]==nowArray[1]){
                    BCG.union(i,j);
                }
            }
        }
        return stones.length - BCG.getcot();
    }
    public class bcg{
        private int cot;
        private int[] parents;
        public bcg(int size){
            cot = size;
            parents = new int[size];
            for(int i=0;i<parents.length;i++){
                parents[i] = i;
            }
        }
        public int findroot(int i){
            if(parents[i]!=i){
                parents[i] = findroot(parents[i]);
            }
            return parents[i];
        }
        public void union(int i, int j){
            int root_i = findroot(i);
            int root_j = findroot(j);
            if(root_i==root_j) return;
            parents[root_i] = root_j;
            cot --;
        }
        public int getcot(){
            return cot;
        }
    }
}

思路2:同样是并查集,但是!考虑x坐标是0到10000之间的10001个点,y坐标是10002到20002之间的10001个点,可降低时间复杂度.为了节约空间(吧),官解使用HashMap来定义parents,初始化时parents为空. 每一次union一组(x,y),会首先执行find(x)和find(y),而find函数中首先是把不存在的节点添加进去(连通图数+1),然后再进行合并
代码2:

class Solution {
    public int removeStones(int[][] stones) {
        findUnion FU = new findUnion(stones.length);
        for(int[] stone:stones){
            FU.union(stone[0], stone[1]+10001);
        }
        return stones.length - FU.get_cot();
    }
    public class findUnion{
        private int cot = 0;
        private HashMap<Integer, Integer> parents;
        public findUnion(int size){
            parents = new HashMap<Integer, Integer>(size);
        }
        public int find(int i){
            if(!parents.containsKey(i)){
                parents.put(i,i);
                cot ++;
            }
            if(parents.get(i)!=i){
                parents.put(i, find(parents.get(i)));
            }
            return parents.get(i);
        }
        public void union(int i, int j){
            int root_i = find(i);
            int root_j = find(j);
            if(root_i == root_j) return;
            parents.put(root_i, root_j);
            cot --;
        }
        public int get_cot(){
            return cot;
        }
    }
    
    
}

34. 337. 打家劫舍 III

题目描述:

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

思路:
定义steal和notsteal两个状态哈希表,每一个root都有两个选择,如果root偷,那么它的左孩子和右孩子一定不偷;如果root不偷,那么它的左孩子和右孩子可以偷可能不偷.

代码1:

class Solution {
    HashMap<TreeNode, Integer> steal = new HashMap<TreeNode, Integer>();
    HashMap<TreeNode, Integer> notsteal = new HashMap<TreeNode, Integer>();
    public int rob(TreeNode root) {
        dfs(root);
        return Math.max(steal.getOrDefault(root,0),notsteal.getOrDefault(root,0));
    }
    public void dfs(TreeNode root){
        if(root==null) return;
        dfs(root.left);
        dfs(root.right);
        int left_steal = steal.getOrDefault(root.left,0);
        int left_notsteal = notsteal.getOrDefault(root.left,0);
        int right_steal = steal.getOrDefault(root.right, 0);
        int right_notsteal = notsteal.getOrDefault(root.right,0);
        steal.put(root, root.val + left_notsteal + right_notsteal);
        notsteal.put(root, Math.max(left_steal, left_notsteal)+Math.max(right_steal, right_notsteal));
    }
}

代码2:用数组存储状态

class Solution {
    HashMap<TreeNode, Integer> steal = new HashMap<TreeNode, Integer>();
    HashMap<TreeNode, Integer> notsteal = new HashMap<TreeNode, Integer>();
    public int rob(TreeNode root) {
        int[] result = dfs(root);
        return Math.max(result[0],result[1]);
    }
    public int[] dfs(TreeNode root){ // 0偷,1不偷
        if(root==null) return new int[2];
        int[] result_left = dfs(root.left);
        int[] result_right = dfs(root.right);
        int[] result_root = new int[2];
        result_root[0] = root.val + result_left[1] + result_right[1];
        result_root[1] = Math.max(result_left[0],result_left[1]) + Math.max(result_right[0], result_right[1]);
        return result_root;
    }
}
在这里插入代码片

35. 面试题 16.19. 水域大小

题目描述:

你有一个用于表示一片土地的整数矩阵land,该矩阵中每个点的值代表对应地点的海拔高度。若值为0则表示水域。由垂直、水平或对角连接的水域为池塘。池塘的大小是指相连接的水域的个数。编写一个方法来计算矩阵中所有池塘的大小,返回值需要从小到大排序。

思路1:dfs
代码2:

class Solution {
    int[] dx = {0,-1,-1,-1,0,1,1,1};
    int[] dy = {-1,-1,0,1,1,1,0,-1};
    int width;
    int height;
    ArrayList<Integer> ans = new ArrayList<>();
    public int[] pondSizes(int[][] land) {
        this.width = land.length;
        this.height = land[0].length;
        for(int i = 0; i < width; i++){
            for(int j = 0; j<height; j++){
                if(land[i][j]==0){
                    ans.add(dfs(i,j,land));
                }
            }
        }
        Collections.sort(ans);
        return ans.stream().mapToInt(Integer::valueOf).toArray();
    }
    public int dfs(int x, int y,int[][] land){
        land[x][y] = 1;
        int cot = 1;
        for(int idx=0;idx<dx.length;idx++){
            int nx = x+dx[idx];
            int ny = y+dy[idx];
            if(in_map(nx,ny)&&land[nx][ny]==0){
                cot += dfs(nx,ny,land);
            }
        }
        return cot;
    }
    public boolean in_map(int x,int y){
        return 0<=x&&x<width&&0<=y&&y<height;
    }
}

思路2:并查集
代码2:

36.117. 填充每个节点的下一个右侧节点指针 II

题目描述:

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。

思路:一定要先遍历右子树!
代码:

class Solution {
    public Node connect(Node root) {
        // 遇到一个节点,判断root是否有左右节点,改变左节点的next为right
        // 判断自己有没有next,如果有,判断next有没有left,如果有root.right.next = root.next.left,如果没有,判断next有没有right,如果有..
        dfs(root);
        return root;
    }
    public void dfs(Node root){
        if(root==null) return;
        if(root.left!=null && root.right!=null){
            root.left.next = root.right;
        }
        Node next_root = root.next;
        while(next_root!=null&&next_root.left==null&&next_root.right==null){
            next_root = next_root.next;
        }
        if(next_root!=null){
            if(root.right!=null){
                if(next_root.left!=null){
                    root.right.next = next_root.left;
                }else{
                    root.right.next = next_root.right;
                }
            }else{
                if(root.left!=null){
                    if(next_root.left!=null){
                        root.left.next = next_root.left;
                    }else{
                        root.left.next = next_root.right;
                    }
                }
            }
        }
        dfs(root.right);
        dfs(root.left);
    }
}

37. 638. 大礼包

题目描述:

在LeetCode商店中, 有许多在售的物品。
然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。
现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。
每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。
任意大礼包可无限次购买。

思路1:
就两种选择:1. 要么我就全买单品 2. 要么我就买部分礼包. 具体怎么买是一个问题,那么我先遍历所有礼包,如果这个礼包我当前可以买,那我就先买了试试,进行递归. 最后比较这两种方案谁比较便宜.

代码1:

class Solution {
    public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        return dfs(price, special, needs);
    }
    public int dfs(List<Integer> price, List<List<Integer>> special, List<Integer> needs){
        int res = 0;
        for(int i = 0; i < price.size(); i ++){
            res += price.get(i) * needs.get(i);
        }
        for(List<Integer>one_special:special){
            List<Integer> clone = new ArrayList<>(needs);
            int i;
            for(i = 0;i<needs.size();i++){
                int diff = needs.get(i) - one_special.get(i);
                if(diff<0) break;
                clone.set(i,diff);
            }
            if(i==needs.size()){
                res = Math.min(res, one_special.get(i)+dfs(price, special, clone));
            }
        }
        return res;
    }
}

思路2:在思路1的基础上,使用HashMap记录已出现的needs状态节点

代码2:

class Solution {
    public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        HashMap<List<Integer>, Integer> map = new HashMap<>();
        return dfs(price, special, needs, map);
    }
    public int dfs(List<Integer> price, List<List<Integer>> special, List<Integer> needs, HashMap<List<Integer>, Integer> map){
        if(map.containsKey(needs)) return map.get(needs);
        int res = 0;
        for(int i = 0; i < price.size(); i ++){
            res += price.get(i) * needs.get(i);
        }
        for(List<Integer>one_special:special){
            List<Integer> clone = new ArrayList<>(needs);
            int i;
            for(i = 0;i<needs.size();i++){
                int diff = needs.get(i) - one_special.get(i);
                if(diff<0) break;
                clone.set(i,diff);
            }
            if(i==needs.size()){
                res = Math.min(res, one_special.get(i)+dfs(price, special, clone, map));
            }
        }
        if(!map.containsKey(needs)) map.put(needs, res);
        return res;
    }
}

38.1254. 统计封闭岛屿的数目

题目描述:

有一个二维矩阵 grid ,每个位置要么是陆地(记号为 0 )要么是水域(记号为 1 )。
我们从一块陆地出发,每次可以往上下左右 4 个方向相邻区域走,能走到的所有陆地区域,我们将其称为一座「岛屿」。
如果一座岛屿 完全 由水域包围,即陆地边缘上下左右所有相邻区域都是水域,那么我们将其称为 「封闭岛屿」。
请返回封闭岛屿的数目。

思路:
深度优先搜索遍历连通图,如果连通图里存在边界点,那么该连通图不算做答案.

代码:

class Solution {
    int height;
    int width;
    int[] dx = {0, -1, 0, 1};
    int[] dy = {-1, 0, 1, 0};
    public int closedIsland(int[][] grid) {
        //从每一块0开始深搜,如果有节点在边界上,那么就不是封闭岛
        this.height = grid.length;
        this.width = grid[0].length;
        int final_ans = 0;
        for(int i = 0;i <grid.length;i++){
            for(int j =0;j<grid[0].length;j++){
                if(grid[i][j]==0){
                    int tmp_ans = dfs(i,j,grid);
                    if(tmp_ans==0) final_ans++;
                }
            }
        }
        return final_ans;
    }
    public int dfs(int i, int j, int[][] grid){
        if(is_boundary(i,j)) return 1;
        int ans = 0;
        for(int idx=0;idx<dx.length;idx++){
            int ni = i + dx[idx];
            int nj = j + dy[idx];
            if(is_in(ni,nj)&&grid[ni][nj]==0){
                grid[ni][nj] = 1;
                ans += dfs(ni,nj,grid);
            }
        }
        return ans;
    }
    public boolean is_in(int i,int j){
        return 0<=i&&i<height&&0<=j&&j<width;
    }
    public boolean is_boundary(int i, int j){
        return i==0||i==(height-1)||j==0||j==(width-1);
    }
}

思路2:改进:并不需要判断is_in,因为如果一个节点不是boundary,那它就不可能访问到其它节点
代码2:

class Solution {
    int height;
    int width;
    int flag;
    int[] dx = {0, -1, 0, 1};
    int[] dy = {-1, 0, 1, 0};
    public int closedIsland(int[][] grid) {
        //从每一块0开始深搜,如果有节点在边界上,那么就不是封闭岛
        this.height = grid.length;
        this.width = grid[0].length;
        int final_ans = 0;
        for(int i = 0;i <grid.length;i++){
            for(int j =0;j<grid[0].length;j++){
                if(grid[i][j]==0){
                    flag = 1;
                    dfs(i,j,grid);
                    final_ans+=flag;
                }
            }
        }
        return final_ans;
    }
    public void dfs(int i, int j, int[][] grid){
        if(is_boundary(i,j)){
            flag = 0;
            return;
        }
        int ans = 0;
        for(int idx=0;idx<dx.length;idx++){
            int ni = i + dx[idx];
            int nj = j + dy[idx];
            if(grid[ni][nj]==0){
                grid[ni][nj] = 1;
                dfs(ni,nj,grid);
            }
        }
    }
    // public boolean is_in(int i,int j){
    //     return 0<=i&&i<height&&0<=j&&j<width;
    // }
    public boolean is_boundary(int i, int j){
        return i==0||i==(height-1)||j==0||j==(width-1);
    }
}

39. 面试题 04.06. 后继者

题目描述:

设计一个算法,找出二叉搜索树中指定节点的“下一个”节点(也即中序后继)。
如果指定节点没有对应的“下一个”节点,则返回null。

思路:
真心不懂

代码:

class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        return dfs(root,p);
    }
    public TreeNode dfs(TreeNode root, TreeNode p){
        if(root==null||p==null){
            return null;
        }
        if(root.val<=p.val){
            return dfs(root.right, p);
        }else{
            TreeNode left_ans = dfs(root.left,p);
            return left_ans == null ? root : left_ans;
        }
    }
}

40. 1306. 跳跃游戏 III

题目描述:

这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。
请你判断自己是否能够跳到对应元素值为 0 的 任一 下标处。
注意,不管是什么情况下,你都无法跳到数组之外。

思路1:

深度优先搜索,每一个位置最多只去一次,最后重新遍历数组,查看元素值为0的位置,你定义的boolean数组是否是true.一共遍历数组两次.

代码1:

class Solution {
    public boolean[] have_visited;
    public boolean canReach(int[] arr, int start) {
        have_visited = new boolean[arr.length];
        dfs(arr, start);
        for(int idx=0;idx<arr.length;idx++){
            if(arr[idx]==0&&have_visited[idx]==true){
                return true;
            }
        }
        return false;
    }
    public void dfs(int[] arr, int start){
        int left_idx = start - arr[start];
        if(left_idx>=0&&have_visited[left_idx]==false){
            have_visited[left_idx] = true;
            dfs(arr, left_idx);
        }
        int right_idx = start + arr[start];
        if(right_idx<arr.length&&have_visited[right_idx]==false){
            have_visited[right_idx] = true;
            dfs(arr, right_idx);
        }
    }
}

思路2:

定义一个result,只遍历数组一次

代码2:

class Solution {
    boolean res;
    boolean[] have_visited;
    public boolean canReach(int[] arr, int start) {
        have_visited = new boolean[arr.length];
        dfs(arr, start);
        return res;
    }
    public void dfs(int[] arr, int start){
        if(arr[start]==0) res = true;
        if(res) return;//!
        int left_idx = start - arr[start];
        if(left_idx>=0&&have_visited[left_idx]==false){
            have_visited[left_idx] = true;
            dfs(arr, left_idx);
        }
        int right_idx = start + arr[start];
        if(right_idx<arr.length&&have_visited[right_idx]==false){
            have_visited[right_idx] = true;
            dfs(arr, right_idx);
        }
    }
}

41.面试题34. 二叉树中和为某一值的路径

和113. 路径总和 II一样

42.756. 金字塔转换矩阵

题目描述:

现在,我们用一些方块来堆砌一个金字塔。 每个方块用仅包含一个字母的字符串表示。
使用三元组表示金字塔的堆砌规则如下:
对于三元组(A, B, C) ,“C”为顶层方块,方块“A”、“B”分别作为方块“C”下一层的的左、右子块。当且仅当(A, B, C)是被允许的三元组,我们才可以将其堆砌上。
初始时,给定金字塔的基层 bottom,用一个字符串表示。一个允许的三元组列表 allowed,每个三元组用一个长度为 3 的字符串表示。
如果可以由基层一直堆到塔尖就返回 true ,否则返回 false 。

思路:
参考https://blog.csdn.net/a1439775520/article/details/105553733
首先对所有可行的三元组进行预处理,组成map.递归中,我们定义两个字符串:bottom,now,分别代表当前层上,所需要的所有叶子节点,和目前已有的叶子节点.当两者长度相差1,说明当前层递归完成,特别的,如果,bottom的长度为2,now的长度为1,那么成功.
代码:

class Solution {
    public boolean pyramidTransition(String bottom, List<String> allowed) {
        HashMap<String, List<String>> map = new HashMap<>();
        for(String allow : allowed){
            String leaf = allow.substring(0,2);
            String root = allow.substring(2,3);
            if(!map.containsKey(leaf)){
                List<String> root_list = new ArrayList<>();
                root_list.add(root);
                map.put(leaf, root_list);
            }
            else{
                map.get(leaf).add(root);
            }
        }
        return dfs(bottom, "", map);
    }
    public boolean dfs(String bottom, String now, HashMap<String, List<String>> map){
        if(bottom.length()==2 && now.length()==1){
            return true;
        }
        if(bottom.length() - now.length()==1){
            return dfs(now, "", map);
        }
        int start = now.length();
        int end = start + 2;
        List<String> root_lst = map.get(bottom.substring(start, end));
        if(root_lst==null) return false;
        for(String root:root_lst){
            if(dfs(bottom, now+root, map)) return true;
        }
        return false;
    }
}

43. 17. 电话号码的字母组合

题目描述:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

思路描述:深度优先搜索,定义一个StringBuffer来暂存结果

代码:

class Solution {
    HashMap<Character, String> str_map = new HashMap<Character, String>();
    public List<String> letterCombinations(String digits) {
        str_map.put('2',"abc");
        str_map.put('3',"def");
        str_map.put('4',"ghi");
        str_map.put('5',"jkl");
        str_map.put('6',"mno");
        str_map.put('7',"pqrs");
        str_map.put('8',"tuv");
        str_map.put('9',"wxyz");
        if(digits.length()==0){
            return new ArrayList<>();
        }
        ArrayList<String> ans_lst = new ArrayList<String>();
        dfs(ans_lst, 0, digits, new StringBuffer());
        return ans_lst;
    }
    public void dfs(ArrayList<String> ans_lst, int index, String digits, StringBuffer tmp_ans){
        if(index == digits.length()){ // learn
            ans_lst.add(tmp_ans.toString());
        }else{
            char d = digits.charAt(index);
            String s = str_map.get(d);
            for(int i = 0; i < s.length(); i++){
                tmp_ans.append(s.charAt(i));
                dfs(ans_lst, index+1, digits, tmp_ans);
                tmp_ans.deleteCharAt(index);
            }
        }
    }
}							 

44.491. 递增子序列

之后不会在CSDN上记录了,为了节约时间,直接在leeetcode上写注释

最后

以上就是迷路菠萝为你收集整理的[java]——leetcode刷题(深度优先搜索)(中等??)(TBC)前言26.526. 优美的排列27.515. 在每个树行中找最大值31. 1110. 删点成林32.547. 省份数量33.947. 移除最多的同行或同列石头34. 337. 打家劫舍 III35. 面试题 16.19. 水域大小36.117. 填充每个节点的下一个右侧节点指针 II37. 638. 大礼包38.1254. 统计封闭岛屿的数目39. 面试题 04.06. 后继者40. 1306. 跳跃游戏 III41.面试的全部内容,希望文章能够帮你解决[java]——leetcode刷题(深度优先搜索)(中等??)(TBC)前言26.526. 优美的排列27.515. 在每个树行中找最大值31. 1110. 删点成林32.547. 省份数量33.947. 移除最多的同行或同列石头34. 337. 打家劫舍 III35. 面试题 16.19. 水域大小36.117. 填充每个节点的下一个右侧节点指针 II37. 638. 大礼包38.1254. 统计封闭岛屿的数目39. 面试题 04.06. 后继者40. 1306. 跳跃游戏 III41.面试所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部