LeetCode 908. 最小差值 I / 1305. 两棵二叉搜索树中的所有元素 / 591. 标签验证器

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 每日一题,题目描述可能不准确,具体还是看力扣里面的题吧

题目描述

给定一个表示代码片段的字符串,你需要实现一个验证器来解析这段代码,并返回它是否合法。合法的代码片段需要遵守以下的所有规则:

  1. 代码必须被合法的闭合标签包围。否则,代码是无效的。
  2. 闭合标签(不一定合法)要严格符合格式:<TAG_NAME>TAG_CONTENT</TAG_NAME>。其中,<TAG_NAME>是起始标签,</TAG_NAME>是结束标签。起始和结束标签中的 TAG_NAME 应当相同。当且仅当 TAG_NAME 和 TAG_CONTENT 都是合法的,闭合标签才是合法的。
  3. 合法的 TAG_NAME 仅含有大写字母,长度在范围 [1,9] 之间。否则,该 TAG_NAME 是不合法的。
  4. 合法的 TAG_CONTENT 可以包含其他合法的闭合标签,cdata (请参考规则7)和任意字符(注意参考规则1)除了不匹配的<、不匹配的起始和结束标签、不匹配的或带有不合法 TAG_NAME 的闭合标签。否则,TAG_CONTENT 是不合法的。
  5. 一个起始标签,如果没有具有相同 TAG_NAME 的结束标签与之匹配,是不合法的。反之亦然。不过,你也需要考虑标签嵌套的问题。
  6. 一个<,如果你找不到一个后续的>与之匹配,是不合法的。并且当你找到一个<或</时,所有直到下一个>的前的字符,都应当被解析为 TAG_NAME(不一定合法)。
  7. cdata 有如下格式:<![CDATA[CDATA_CONTENT]]>。CDATA_CONTENT 的范围被定义成 <![CDATA[ 和后续的第一个 ]]>之间的字符。
  8. 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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值