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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2021.7.27 每日一题
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
更正式地说,root.val = min(root.left.val, root.right.val) 总成立。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。
输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。
示例 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);
}
}