LeetCode1736. 替换隐藏数字得到的最晚时间/1743. 从相邻元素对还原数组/671. 二叉树中第二小的节点

1736. 替换隐藏数字得到的最晚时间

2021.7.24 每日一题,最近都不难

题目描述

给你一个字符串 time ,格式为 hh:mm(小时:分钟),其中某几位数字被隐藏(用 ? 表示)。

有效的时间为 00:00 到 23:59 之间的所有时间,包括 00:00 和 23:59 。

替换 time 中隐藏的数字,返回你可以得到的最晚有效时间。

示例 1:

输入:time = “2?:?0”
输出:“23:50”
解释:以数字 ‘2’ 开头的最晚一小时是 23 ,以 ‘0’ 结尾的最晚一分钟是 50 。

示例 2:

输入:time = “0?:3?”
输出:“09:39”

示例 3:

输入:time = “1?:22”
输出:“19:22”

提示:

time 的格式为 hh:mm
题目数据保证你可以由输入的字符串生成有效的时间

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/latest-time-by-replacing-hidden-digits
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

我本以为从低到高判断就不需要判断那么多情况的,结果不行,改了好几次,要是周赛完了…

class Solution {
    public String maximumTime(String time) {
        char[] cc = time.toCharArray();
        int l = cc.length;
        if(cc[4] == '?')
            cc[4] = '9';
        if(cc[3] == '?')
            cc[3] = '5';
        if(cc[0] == '2' && cc[1] == '?'){
            cc[1] = '3';
        }else if(cc[0] == '?'){
            if(cc[1] == '?'){
                cc[0] = '2';
                cc[1] = '3';
            }
            else if(cc[1] >= '4')
                cc[0] = '1';
            else
                cc[0] = '2';
        }
        else{
            if(cc[1] == '?')
                cc[1] = '9';
        } 
        return new String(cc);
    }
}

还是官解优雅:

class Solution {
    public String maximumTime(String time) {
        char[] arr = time.toCharArray();
        if (arr[0] == '?') {
            arr[0] = ('4' <= arr[1] && arr[1] <= '9') ? '1' : '2';
        }
        if (arr[1] == '?') {
            arr[1] = (arr[0] == '2') ? '3' : '9';
        }
        if (arr[3] == '?') {
            arr[3] = '5';
        }
        if (arr[4] == '?') {
            arr[4] = '9';
        }
        return new String(arr);
    }
}


作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/latest-time-by-replacing-hidden-digits/solution/ti-huan-yin-cang-shu-zi-de-dao-de-zui-wa-0s7r/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1743. 从相邻元素对还原数组

2021.7.25 每日一题

题目描述

存在一个由 n 个不同元素组成的整数数组 nums ,但你已经记不清具体内容。好在你还记得 nums 中的每一对相邻元素。

给你一个二维整数数组 adjacentPairs ,大小为 n - 1 ,其中每个 adjacentPairs[i] = [ui, vi] 表示元素 ui 和 vi 在 nums 中相邻。

题目数据保证所有由元素 nums[i] 和 nums[i+1] 组成的相邻元素对都存在于 adjacentPairs 中,存在形式可能是 [nums[i], nums[i+1]] ,也可能是 [nums[i+1], nums[i]] 。这些相邻元素对可以 按任意顺序 出现。

返回 原始数组 nums 。如果存在多种解答,返回 其中任意一个 即可。

示例 1:

输入:adjacentPairs = [[2,1],[3,4],[3,2]]
输出:[1,2,3,4]
解释:数组的所有相邻元素对都在 adjacentPairs 中。
特别要注意的是,adjacentPairs[i] 只表示两个元素相邻,并不保证其 左-右 顺序。
示例 2:

输入:adjacentPairs = [[4,-2],[1,4],[-3,1]]
输出:[-2,4,1,-3]
解释:数组中可能存在负数。
另一种解答是 [-3,1,4,-2] ,也会被视作正确答案。
示例 3:

输入:adjacentPairs = [[100000,-100000]]
输出:[100000,-100000]

提示:

nums.length == n
adjacentPairs.length == n - 1
adjacentPairs[i].length == 2
2 <= n <= 105
-105 <= nums[i], ui, vi <= 105
题目数据保证存在一些以 adjacentPairs 作为元素对的数组 nums

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/restore-the-array-from-adjacent-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

我这个思路怎么说呢,不知道是不是最简单的,但是超过百分之80还行吧
首先得由题意得到这样一个规律,就是最后输出数组中,首尾数字在原数组中是出现了一次,而其他数字在原数组中都出现过两次
所以说,找到出现一次的数字,也就找到了开头和结尾

但是找到开头以后怎么把后面的数字连接起来呢
想了一会想到了用一个list存储每个数字出现的数组中的下标,然后把它当做值,这个数当做键存储在哈希表中
然后先找出现一次的数字,也就是这个数字对应的list大小为1
找到以后,就开始连接结果数组。具体来说,就是找这个数字对应的数组中的另一个数字,然后将它拼接到后面。如果list中有两个数组,那么肯定有一个数组是和之前重复的,就直接看另一个不重复的数组,找出其中不重复的数字
就这样依次将结果数组填满

class Solution {
    public int[] restoreArray(int[][] adjacentPairs) {
        //只有两边的数字出现过一次,其他数字都出现过两次,只要找到这两个只出现一次的数字
        //然后以这两组中的任意一组开头,后面首尾相连就可以了
        //主要是怎么找首尾相连的数
        //我想到一个思路就是将每个数存在的数组放在哈希表中,键是那个数,值是两个数组(或者1个)
        //然后以一个数组的数开头,在哈希表中找它的值对应的键,然后在键中,再找对应的值,这样一次循环就找到了

        Map<Integer, List<Integer>> map = new HashMap<>();

        int l = adjacentPairs.length;
        for(int i = 0; i < l; i++){
            int num1 = adjacentPairs[i][0];
            int num2 = adjacentPairs[i][1];
            List<Integer> list1 = map.getOrDefault(num1, new ArrayList<>());
            List<Integer> list2 = map.getOrDefault(num2, new ArrayList<>());
            list1.add(i);
            list2.add(i);
            map.put(num1, list1);
            map.put(num2, list2);
        }
        int start = 0;
        int temp = 0;
        int pre = 0;    //上一个用过的数组下标
        for(Map.Entry<Integer, List<Integer>> entry : map.entrySet()){
            List<Integer> list = entry.getValue();
            if(list.size() == 1){
                start = entry.getKey();
                int[] nums = adjacentPairs[list.get(0)];
                pre = list.get(0);
                temp = nums[0] == start ? nums[1] : nums[0];
                break;
            }
        }
        int[] res = new int[l + 1];
        res[0] = start;
        res[1] = temp;
        for(int i = 2; i < l + 1; i++){
            List<Integer> list = map.get(temp);
            int id1 = list.get(0);
            int id2 = list.get(1);
            pre = pre == id1 ? id2 : id1;
            res[i] = adjacentPairs[pre][0] == temp ? adjacentPairs[pre][1] : adjacentPairs[pre][0];
            temp = res[i];
        }
        return res;
    }
}

官解思路就和我这个差不多
三叶姐的双向构造,绝了
这里有一句话不太理解:
我们可以利用 ansans 的长度为 2 <= n <= 10^5, 构造一个长度 10^6 的数组 q(这里可以使用 static 进行加速,让多个测试用例共享一个大数组)。

class Solution {
    static int N = (int)1e6+10;
    static int[] q = new int[N];
    public int[] restoreArray(int[][] aps) {
        int m = aps.length, n = m + 1;
        //这一步与之前一样,也是处理一个存放相邻关系的map
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int[] ap : aps) {
            int a = ap[0], b = ap[1];
            List<Integer> alist =  map.getOrDefault(a, new ArrayList<>());
            alist.add(b);
            map.put(a, alist);
            List<Integer> blist = map.getOrDefault(b, new ArrayList<>());
            blist.add(a);
            map.put(b, blist);
        }
        //然后找到中心点,准备向两端扩展
        int l = N / 2, r = l + 1;
        int std = aps[0][0];
        List<Integer> list = map.get(std);
        //中心位置放std
        q[l--] = std;
        //左右两边放相邻的两个数
        q[r++] = list.get(0);
        //因为有可能就有一个和它相邻,所以这里需要判断一下list的大小
        if (list.size() > 1) q[l--] = list.get(1);

        while ((r - 1) - (l + 1) + 1 < n) {
            //找到与当前左边位置相邻的数,然后,扩展左边
            List<Integer> alist = map.get(q[l + 1]);
            int j = l;
            for (int i : alist) {
                if (i != q[l + 2]) q[j--] = i;
            }
            l = j;
            //扩展右边
            List<Integer> blist = map.get(q[r - 1]);
            j = r;
            for (int i : blist) {
                if (i != q[r - 2]) q[j++] = i;
            }
            r = j;
        }
        int[] ans = new int[n];
        for (int i = l + 1, idx = 0; idx < n; i++, idx++) {
            ans[idx] = q[i];
        }
        return ans;
    }
}

作者:AC_OIer
链接:https://leetcode-cn.com/problems/restore-the-array-from-adjacent-pairs/solution/gong-shui-san-xie-yi-ti-shuang-jie-dan-x-elpx/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

671. 二叉树中第二小的节点

2021.7.27 每日一题

题目描述

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。

更正式地说,root.val = min(root.left.val, root.right.val) 总成立。

给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

示例 1:
LeetCode1736. 替换隐藏数字得到的最晚时间/1743. 从相邻元素对还原数组/671. 二叉树中第二小的节点_第1张图片

输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。
示例 2:
LeetCode1736. 替换隐藏数字得到的最晚时间/1743. 从相邻元素对还原数组/671. 二叉树中第二小的节点_第2张图片

输入:root = [2,2,2]
输出:-1
解释:最小的值是 2, 但是不存在第二小的值。

提示:

树中节点数目在范围 [1, 25] 内
1 <= Node.val <= 231 - 1
对于树中每个节点 root.val == min(root.left.val, root.right.val)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/second-minimum-node-in-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

刚开始看成了第二大的
第二小的话,首先根节点就是最小的,然后在左右子树找不同于根节点,且最小的值。之所以写成long,是因为用例有个整数的最大值…
我这样写不知道是不是最好的方法,感觉应该能更简单

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int t;
    public int findSecondMinimumValue(TreeNode root) {
        //第二小,我想成第二大了...
        //那么,树根位置的值是最小的肯定
        //然后在树中找最小的值
        t = root.val;
        long left = dfs(root);
        long right = dfs(root);
        if(left != Long.MAX_VALUE || right != Long.MAX_VALUE)
            return (int)Math.min(left, right);
        else
            return -1;
    }

    public long dfs(TreeNode node){
        if(node == null){
            return Long.MAX_VALUE;
        }
        if(node.val != t)
            return node.val;
        long left = dfs(node.left);
        long right = dfs(node.right);
        return Math.min(left, right);
    }
}

看了几个解法,思路差不多,再写一个用成员变量的

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int t;
    int res = -1;
    public int findSecondMinimumValue(TreeNode root) {
        //第二小,我想成第二大了...
        //那么,树根位置的值是最小的肯定
        //然后在树中找最小的值
        t = root.val;
        dfs(root);
        return res;
    }

    public void dfs(TreeNode node){
        if(node == null){
            return;
        }
        if(res != -1 && node.val > res)
            return;
        
        if(node.val > t)
            res = node.val;
        
        dfs(node.left);
        dfs(node.right);
    }
}

你可能感兴趣的:(LeetCode,java,leetcode)