908. 最小差值 I
2022.4.30 每日一题
题目描述
给你一个整数数组 nums,和一个整数 k 。
在一个操作中,您可以选择 0 <= i < nums.length 的任何索引 i 。将 nums[i] 改为 nums[i] + x ,其中 x 是一个范围为 [-k, k] 的整数。对于每个索引 i ,最多 只能 应用 一次 此操作。
nums 的 分数 是 nums 中最大和最小元素的差值。
在对 nums 中的每个索引最多应用一次上述操作后,返回 nums 的最低 分数 。
示例 1:
输入:nums = [1], k = 0
输出:0
解释:分数是 max(nums) - min(nums) = 1 - 1 = 0。
示例 2:
输入:nums = [0,10], k = 2
输出:6
解释:将 nums 改为 [2,8]。分数是 max(nums) - min(nums) = 8 - 2 = 6。
示例 3:
输入:nums = [1,3,6], k = 3
输出:0
解释:将 nums 改为 [4,4,4]。分数是 max(nums) - min(nums) = 4 - 4 = 0。
提示:
1 <= nums.length <= 10^4
0 <= nums[i] <= 10^4
0 <= k <= 10^4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-range-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
class Solution {
public int smallestRangeI(int[] nums, int k) {
//分数差是由最大最小值决定的,如果最大值小值能行,其他也肯定行
int max = 0;
int min = 100000;
for(int n : nums){
max = Math.max(max, n);
min = Math.min(min, n);
}
max -= k;
min += k;
if(max <= min)
return 0;
else
return max - min;
}
}
1305. 两棵二叉搜索树中的所有元素
2022.5.1 每日一题
题目描述
给你 root1 和 root2 这两棵二叉搜索树。请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。.
示例 1:
输入:root1 = [2,1,4], root2 = [1,0,3]
输出:[0,1,1,2,3,4]
示例 2:
输入:root1 = [1,null,8], root2 = [8,1]
输出:[1,1,8,8]
提示:
每棵树的节点数在 [0, 5000] 范围内
-10^5 <= Node.val <= 10^5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/all-elements-in-two-binary-search-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
学习两个List中的方法
list.addAll(Collection<> c)
list.subList(from, to)
class Solution {
public List<Integer> getAllElements(TreeNode root1, TreeNode root2) {
List<Integer> nums1 = new ArrayList<Integer>();
List<Integer> nums2 = new ArrayList<Integer>();
inorder(root1, nums1);
inorder(root2, nums2);
List<Integer> merged = new ArrayList<Integer>();
int p1 = 0, p2 = 0;
while (true) {
if (p1 == nums1.size()) {
//list.addAll(Collection<> c)
//list.subList(from, to)
merged.addAll(nums2.subList(p2, nums2.size()));
break;
}
if (p2 == nums2.size()) {
merged.addAll(nums1.subList(p1, nums1.size()));
break;
}
if (nums1.get(p1) < nums2.get(p2)) {
merged.add(nums1.get(p1++));
} else {
merged.add(nums2.get(p2++));
}
}
return merged;
}
public void inorder(TreeNode node, List<Integer> res) {
if (node != null) {
inorder(node.left, res);
res.add(node.val);
inorder(node.right, res);
}
}
}
591. 标签验证器
2022.5.2 每日一题,题目描述可能不准确,具体还是看力扣里面的题吧
题目描述
给定一个表示代码片段的字符串,你需要实现一个验证器来解析这段代码,并返回它是否合法。合法的代码片段需要遵守以下的所有规则:
- 代码必须被合法的闭合标签包围。否则,代码是无效的。
- 闭合标签(不一定合法)要严格符合格式:<TAG_NAME>TAG_CONTENT</TAG_NAME>。其中,<TAG_NAME>是起始标签,</TAG_NAME>是结束标签。起始和结束标签中的 TAG_NAME 应当相同。当且仅当 TAG_NAME 和 TAG_CONTENT 都是合法的,闭合标签才是合法的。
- 合法的 TAG_NAME 仅含有大写字母,长度在范围 [1,9] 之间。否则,该 TAG_NAME 是不合法的。
- 合法的 TAG_CONTENT 可以包含其他合法的闭合标签,cdata (请参考规则7)和任意字符(注意参考规则1)除了不匹配的<、不匹配的起始和结束标签、不匹配的或带有不合法 TAG_NAME 的闭合标签。否则,TAG_CONTENT 是不合法的。
- 一个起始标签,如果没有具有相同 TAG_NAME 的结束标签与之匹配,是不合法的。反之亦然。不过,你也需要考虑标签嵌套的问题。
- 一个<,如果你找不到一个后续的>与之匹配,是不合法的。并且当你找到一个<或</时,所有直到下一个>的前的字符,都应当被解析为 TAG_NAME(不一定合法)。
- cdata 有如下格式:<![CDATA[CDATA_CONTENT]]>。CDATA_CONTENT 的范围被定义成 <![CDATA[ 和后续的第一个 ]]>之间的字符。
- CDATA_CONTENT 可以包含任意字符。cdata 的功能是阻止验证器解析CDATA_CONTENT,所以即使其中有一些字符可以被解析为标签(无论合法还是不合法),也应该将它们视为常规字符。
合法代码的例子:
输入: “<DIV>This is the first line <![CDATA[< div>]]></DIV>”(div前面没有空格)
输出: True解释:
代码被包含在了闭合的标签内: <DIV> 和 </DIV> 。
TAG_NAME 是合法的,TAG_CONTENT 包含了一些字符和 cdata 。
即使 CDATA_CONTENT 含有不匹配的起始标签和不合法的 TAG_NAME,它应该被视为普通的文本,而不是标签。
所以 TAG_CONTENT 是合法的,因此代码是合法的。最终返回True。
输入: “<DIV>>> ![cdata[]] <![CDATA[< div>]>]]>]]>>]</DIV>”
输出: True解释:
我们首先将代码分割为: start_tag|tag_content|end_tag 。
start_tag -> “<DIV>”
end_tag -> “</DIV>”
tag_content 也可被分割为: text1|cdata|text2 。
text1 -> ">> ![cdata[]] "
cdata -> “<![CDATA[< div>]>]]>” ,其中 CDATA_CONTENT 为 “< div>]>”
text2 -> “]]>>]”
start_tag 不是 “>>” 的原因参照规则 6 。
cdata 不是 “<![CDATA[]>]]>]]>” 的原因参照规则 7 。
不合法代码的例子:
输入: “<A> <B> </A> </B>”
输出: False
解释: 不合法。如果 “<A>” 是闭合的,那么 “<B>” 一定是不匹配的,反之亦然。
输入: “<DIV> div tag is not closed <DIV>”
输出: False
输入: “<DIV> unmatched < </DIV>”
输出: False
输入: “<DIV> closed tags with invalid tag name <b>123</b> </DIV>”
输出: False
输入: “<DIV> unmatched tags with invalid tag name </1234567890> and <CDATA[[]]> </DIV>”
输出: False
输入: “<DIV> unmatched start tag <B> and unmatched end tag </C> </DIV>”
输出: False
注意:
为简明起见,你可以假设输入的代码(包括提到的任意字符)只包含数字, 字母, ‘<’,‘>’,‘/’,‘!’,‘[’,']‘和’ '。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/tag-validator
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
官解这个写法就挺简单的,用indexOf()找对应的字符位置,更加简洁,且不容易出错
class Solution {
public boolean isValid(String code) {
//就和那种判断括号匹配差不多
//首先找TAG,如果遇到一个<, 那么就找>,中间的部分就是TAG
//判断TAG就是看是不是大写字母,长度
//将TAG放入栈中,继续遍历,正常字符就直接跳过
//如果遇到了结束标签,那么弹出栈顶的标签,看是否匹配,不匹配false,匹配继续
//如果此时栈为空了,但是还没有遍历完,说明没有被闭合标签包围,false
//遇到cdata那种形式,将起始标志放在栈中,后续看结束标志
Deque<String> stack = new LinkedList<>();
int l = code.length();
int idx = 0;
while(idx < l){
char c = code.charAt(idx);
//System.out.println(idx);
//如果是左括号,那么是标签或者cdata
if(c == '<'){
if(idx == l - 1)
return false;
//如果是结束标签
if(code.charAt(idx + 1) == '/'){
//找后面第一个>
int end = code.indexOf('>', idx);
if(end == -1)
return false;
String tagname = code.substring(idx + 2, end);
if(stack.isEmpty() || !stack.pop().equals(tagname))
return false;
idx = end + 1;
//如果此时栈是空的,但是还没有遍历到最后,那么说明不是在闭合标签里,false,参考错误示例1
if(stack.isEmpty() && idx != l)
return false;
//如果不是感叹号,那么应该是一个标签
}else if(code.charAt(idx + 1) != '!'){
int end = code.indexOf('>', idx);
if(end == -1)
return false;
String tagname = code.substring(idx + 1, end);
//长度要求
if(tagname.length() < 1 || tagname.length() > 9)
return false;
//如果不是大写字母,false
for(int i = idx + 1; i < end; i++){
if(!Character.isUpperCase(code.charAt(i)))
return false;
}
stack.push(tagname);
idx = end + 1;
//如果是!,那么判断是不是cdata,不是false
}else{
//如果此时栈为空,false
if(stack.isEmpty())
return false;
//如果长度直接超过了,false
if(idx + 9 > l)
return false;
String cdata = code.substring(idx + 2, idx + 9);
if(!"[CDATA[".equals(cdata))
return false;
//找结束标志
int end = code.indexOf("]]>", idx);
if(end == -1)
return false;
idx = end + 3;
}
//如果遇到了其他字符,需要保证是在一个闭合标签里面,所以加一个栈为空的判断
}else{
if(stack.isEmpty())
return false;
idx++;
}
}
return stack.isEmpty();
}
}