591. 标签验证器 / 剑指 Offer II 024. 反转链表 / 剑指 Offer II 025. 链表中的两数相加

591. 标签验证器【困难题】【每日一题】

思路:

分类讨论,我分不明白,对答案的写法加了注释。

代码:

class Solution {
    public boolean isValid(String code) {
        int n = code.length();
        char[] chars = code.toCharArray();
        Deque<String> deque = new ArrayDeque<>();
        int i = 0;
        while (i < n){
            //遇到 <
            if (chars[i] == '<'){
                //如果是在code结尾,直接返回false
                if (i == n-1){
                    return false;
                }
                //不在code结尾的话,判断这是单纯的 < (左标签)还是 </ (右标签)还是 <! (cdata)
                //如果是 </ 说明这是右标签
                if (chars[i+1] == '/'){
                    //求出code字符串中从 i 位置往右遇到的第一个 > 的位置
                    int j = code.indexOf('>',i);
                    //如果 j < 0 说明没找到 那么说明右标签没有闭合,返回false
                    if (j < 0){
                        return false;
                    }
                    //取出标签名
                    String tagName = code.substring(i+2,j);
                    //判断队列 deque 中是否为空 或者 队列顶部需要闭合的左标签是否与当前这个右标签名字相同
                    if (deque.isEmpty() || !deque.peek().equals(tagName)){
                        //如果为空 说明没有待匹配的左标签 ; 如果 不相同 说明当前右标签与左标签不匹配,均不合法,返回false
                        return false;
                    }
                    //能走到这里说明右标签与左标签匹配成功,queue中删除待匹配的左标签
                    deque.pop();
                    //更新待判断的下标
                    i = j+1;
                    //如果deque就此空了 且 i 不在字符串结尾处 那么说明左右标签都已经闭合关闭,但仍有字符在标签之外,此时字符串依然不合法
                    if (deque.isEmpty() && i != n){
                        return false;
                    }
                }else if (chars[i+1] == '!'){// cdata
                    //先判断deque是否为空,因为cdata只能出现在标签体内,如果已经出现了cdata,在它之前却没有左标签出现,那么一定是不合法的
                    if (deque.isEmpty()){
                        return false;
                    }
                    //cdata 的 左侧固定字符为 <![CDATA[ 如果从i往右数第9位就已经超出 code了,说明连cdata都不合法,更别提cdata右侧还得有 右标签
                    if (i + 9 > n){
                        return false;
                    }
                    //截取 code中 cdata体 的左侧固定字符长度
                    String cdata = code.substring(i+2,i+9);
                    //判断与标准左侧固定字符( [CDATA[ )是否匹配
                    if (!"[CDATA[".equals(cdata)){
                        //不匹配直接返回false
                        return false;
                    }
                    //求 ]]> 这个cdada的右侧固定字符串在code中 i位置往右第一次出现的位置下标
                    int j = code.indexOf("]]>",i);
                    //如果没有出现,说明cdata无法闭合,返回false
                    if (j < 0){
                        return false;
                    }
                    //更新待判断的下标
                    i = j+3;
                }else {//  左标签
                    //求出当前 < 右侧第一个 > 的下标 
                    int j = code.indexOf('>',i);
                    //如果不存在,说明不合法,返回false
                    if (j < 0){
                        return false;
                    }
                    //求出标签名
                    String tagName = code.substring(i+1,j);
                    //判断标签名长度是否合法,合法长度为 [1,9]
                    if (tagName.length() < 1 || tagName.length() > 9){
                        return false;
                    }
                    //判断标签名是否均为大写字母,合法应为全部大写
                    for (char c : tagName.toCharArray()) {
                        if (!Character.isUpperCase(c)){
                            return false;
                        }
                    }
                    //将标签名压入栈 
                    deque.push(tagName);
                    //更新待判断的下标
                    i = j+1;
                }
            }else {//没有遇到 < 说明这就是普通文本,直接跳过即可
                //不过要判断此时是否有标签尚未闭合,如果标签已全部闭合却遇到了普通文本,那么这是不合法的
                if (deque.isEmpty()){
                    return false;
                }
                i++;
            }
        }
        //当code遍历结束,如果是合法的,那么此时标签完全闭合,deque是空的
        return deque.isEmpty();
    }
}

剑指 Offer II 024. 反转链表【简单题】

思路:【迭代】

定义一个正向链表,指针cur初始指向head,定义一个逆向链表,指针pre初始指向null
正向遍历链表,同时将遍历到的节点cur原来的指向断开,指向pre节点,然后更新precur节点。
最后返回pre指向的链表。

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        while(cur != null){
            //定义正向链表中 cur的下一个节点
            ListNode next = cur.next;
            //将cur的下一个节点指向 pre
            cur.next = pre;
            //将pre更新为当前cur节点
            pre = cur;
            //继续遍历正向链表,将cur更新为原本的下一个节点
            cur = next;
        }
        return pre;
    }
}

剑指 Offer II 025. 链表中的两数相加【中等题】

思路1【反转链表】

利用024题 反转链表,将传入链表l1l2反转后对应位进行相加进位。
将所得的结果存入新的节点并放在ans链表头部。
最后返回ans链表。

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //反转 l1 和 l2
        ListNode r1 = reverseList(l1),r2 = reverseList(l2);
        //进位标志位
        int add = 0;
        //表示 和 的链表,初始为 null
        ListNode ans = null;
        //当 r1不为空 或 r2不为空 或 仍有进位
        while(r1 != null || r2 != null || add != 0){
            int x1 = r1 == null ? 0 : r1.val;//求出r1的值
            int x2 = r2 == null ? 0 : r2.val;//求出r2的值
            int sum = x1 + x2 + add;//相加
            add = sum / 10;//求进位
            sum = sum % 10;//当前位的和
            //建立表示当前位的 和节点
            ListNode curNode = new ListNode(sum);
            //将和节点指向ans
            curNode.next = ans;
            //ans更新为和节点
            ans = curNode;
            //遍历r1的下一位
            if (r1 != null){
                r1 = r1.next;
            }
            //遍历r2的下一位
            if (r2 != null){
                r2 = r2.next;
            }
        }
        return ans;
    }
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        while(cur != null){
            //定义正向链表中 cur的下一个节点
            ListNode next = cur.next;
            //将cur的下一个节点指向 pre
            cur.next = pre;
            //将pre更新为当前cur节点
            pre = cur;
            //继续遍历正向链表,将cur更新为原本的下一个节点
            cur = next;
        }
        return pre;
    }
}

思路2【栈】【进阶版不反转链表解答此题】【题解】

遍历两个链表,将其值压入栈,然后再依次取出栈顶元素相加求进位。
将所得的结果建立新的节点并放在ans链表头部。
最后返回ans链表。

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new ArrayDeque<Integer>();
        Deque<Integer> stack2 = new ArrayDeque<Integer>();
        while (l1 != null) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;
        ListNode ans = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            int a = stack1.isEmpty() ? 0 : stack1.pop();
            int b = stack2.isEmpty() ? 0 : stack2.pop();
            int cur = a + b + carry;
            carry = cur / 10;
            cur %= 10;
            ListNode curnode = new ListNode(cur);
            curnode.next = ans;
            ans = curnode;
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值