算法练习随记(五)

1. 把二叉搜索树转换为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  1. 节点的左子树仅包含键 小于 节点键的节点。
  2. 节点的右子树仅包含键 大于 节点键的节点。
  3. 左右子树也必须是二叉搜索树。

示例 1:

在这里插入图片描述

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

输入:root = [0,null,1]
输出:[1,null,1]

我的解法(无脑递归)

class Solution {
    int num = 0;
    public TreeNode convertBST(TreeNode root) {
        if(root != null){
            convertBST(root.right);
            root.val += num;
            num = root.val;
            convertBST(root.left);
            return root;
        }
        return null;
    }
}

递归这个东西,我也很迷,只能说多刷了,没准哪天悟了!

2. 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]
输出:1
示例 2:

输入:grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出:3

我的解法(递归)

class Solution {
    public int numIslands(char[][] grid) {
        // 何为岛屿? 只要(i,j) 水平或竖直方向有陆地(坐标值为1)与坐标(i,j)直接相连
        // 这些坐标也属于岛屿的一部分,我们以某个陆地坐标为中心,不断向它四周扩散(递归)、
        // 知道所有扩散终止(遇到海洋或者边界),同时扩散过程中遇到的陆地坐标全部标记为 0
        // 这样做是为了避免后续遍历重复进行扩散
        // 最后统计有几个扩散过程,即为岛屿数量

        // 统计岛屿数量
        int res = 0;

        for(int i = 0; i < grid.length; ++i){
            for(int j = 0; j < grid[0].length; ++j){
                if(grid[i][j] == '1'){
                    // grid[i][j] = 1 说明是陆地坐标,开始扩散
                    dfs(grid, i, j);
                    // 扩散完成 岛屿数量+1
                    res++;
                }

            }
        }

        return res;
    }

    public void dfs(char[][] grid, int i, int j){
        // 如果遇到海洋坐标 或者 到达边界 停止扩散
        // grid[i][j] == '0' 这个放在最后 利用短路特性 否则会出现数组下标越界
        if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0')    return;
        
        // 将散过程中遇到的陆地坐标全部标记为 0,避免后续遍历重复进行扩散
        grid[i][j] = '0';

        // 向四周扩散
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }

}

今天想和大家说点心里话,我刷算法题有一段时间了,但是说实话一直还处于在算法大门外面徘徊的样子。做题时很少能够立刻看出思路,其实这道题我之前也刷到过类似的,但是今天做,其实还是很懵逼,甚至于一开始连题都读不懂,如果是以前的话,我可能会绝望,但是现在,被打击习惯了,脸皮也就厚一点了,实在不懂,就看看题解,然后自己去理解,再自己写出来。但我总觉得自己在算法这条路上很难,或者说是天赋有限,当然可能也是没有那么多时间去刷题,去总结。

我说这些不是劝退大家,更不是宣泄自己的负能量,这是不可能的,这不是我写博客的初衷,我只是想和大家说一说,可能很多人都会遇到我这种情况,也处在迷茫中。

希望你看到这里,能够缓解一下自己的情绪,至少,这种迷茫无力感觉不是只有你一个人有,至少,我现在还是这样。一起加油吧,我也期待将来我也能够从容地面对算法,面对我的不足,感谢大家听我废话。

3. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

我的解法(暴力破解,会超时)

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] res = new int[temperatures.length];
        for(int i = 0; i < temperatures.length - 1; ++i){
            for(int j = i + 1; j < temperatures.length; ++j){
                if(temperatures[j] > temperatures[i]){
                    res[i] = j - i;
                    break;
                }
            }
        }
        return res;
    }
}

我的解法(动态规划)

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        /**
         * 这道题我们可以试着倒着推导 最后一天后面显然不会有比它还高的,所以直接为0
         * 再看倒数第二天,如果最后一天的气温比他高,那就结果为 1,否则为 0
         * 到这里,我们可以这样假设,是不是我们想要知道第 i 天的结果,只需要知道第 i+1 天的结果
         * 如果T[i] < T[i+1] 那么 res[i] = 1
         * 如果T[i] > T[i+1] 
         *     如果 res[i+1] = 0,那么显然 T[i] = 0
         *     如果 res[i+1] != 0 那就比较 T[i] 和 T[i+1+res[i+1]]
         */
        int len = temperatures.length;
        int[] res = new int[len];
        for(int i = len - 2; i >= 0; i--){
           for(int j = i + 1; j < len; j += res[j]){
               if(temperatures[i] < temperatures[j]){
                   res[i] = j - i;
                   break;
               }else if(res[j] == 0){
                   res[i] = 0;
                   break;
               }
           }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上阡陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值