华为OD刷题C卷 - 每日刷题 23(提取字符串中的最长表达式,模拟目录管理功能 - 完整实现)

1、提取字符串中的最长表达式

目标是从一个给定的字符串中提取出最长的合法简单数学表达式,并计算该表达式的值。如果存在多个同样长度的合法表达式,则选择第一个出现的表达式进行计算。

简单数学表达式的规则:

只包含0-9的数字和+、-、*三种运算符。

所有数字的计算结果不超过long类型的最大值。

表达式中操作符不能连续出现,例如"±-+1"是非法的。

如果有多个相同长度的合法表达式,选择第一个出现的表达式。

表达式必须是最长的合法表达式。

2、(模拟目录管理功能 - 完整实现):

这段 Java 代码是模拟目录管理功能的完整实现。它定义了 Main 类和两个辅助类 TreeNode 与 Tree。Tree 类包含了目录树的数据结构和基本操作,如创建目录、切换目录和获取当前路径。

main 方法处理标准输入中的命令序列,并根据命令更新目录树的状态,最终输出最后一条命令的执行结果。

java 复制代码
// Hard.java

package OD340;

import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description 提取字符串中的最长表达式
 * @level 7
 * @score 100
 * @type 双指针、正则表达式、栈
 */


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Hard {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        System.out.println(getMaxMath(str));

    }

    //提取字符串中最长合法表达式并计算值(只包含两个操作数的,且第一个数带正负号),如有多个长度一样,则返回第一个
    public static long getMaxMath(String str) {
        char[] chars = str.toCharArray();
        int n = chars.length;
        //创建正则 匹配 (带正负号0个或1个) 数字1个或多个,然后是 + - * 必须1个 ,然后是 (不带正负号的数字)1个或多个
        //Pattern pattern = Pattern.compile("^([+-]?\\d+)([+*-]{1}\\d+)$");
        //如果匹配不只两个操作数
        Pattern pattern = Pattern.compile("^([+-]?\\d+)(([+*-]\\d+)+)([+*-]\\d+)$");

        int max = 0;
        long sum = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                String sub = str.substring(i, j + 1);
                Matcher matcher = pattern.matcher(sub);
                //如果匹配成功,且长度大于当前保存的最长,则更新
                if (matcher.find() && sub.length() > max) {
                    max = sub.length();
                    sum = cal(sub);
                }
            }
        }
        return sum;
    }


    //计算合法且无括号表达式的值:如 1 + 2 * 3 返回 7
    public static long cal(String str) {
        char[] chars = str.toCharArray();
        int n = chars.length;
        //存放操作数
        Stack<Long> stack = new Stack<>();
        //初始化符号和数字
        long number = 0;
        char sign = '+';
        //默认符号为"+" 即使第一位是-1 会+0 再 -1
        for (int i = 0; i < n; i++) {
            char c = chars[i];
            //如果遇到数字,拼数字
            if (c >= '0' && c <= '9') {
                number = number * 10 + (c - '0');
            }
            //没有括号和空格等不合法行为
            //遇到符号或已经到最后一位,将数字入栈、并刷新符号和数字
            if (!Character.isDigit(c) || i == n - 1) {
                if (sign == '+') {
                    //该数字前面符号是"+"直接入栈
                    stack.push(number);
                } else if (sign == '-') {
                    //该数字前面的符号是"-",变负数后入栈
                    stack.push(-1 * number);
                } else if (sign == '*') {
                    //该数字前面是乘,弹出一个相乘后再入栈
                    stack.push(stack.pop() * number);
                }
                //刷新符号
                sign = c;
                //刷新数字
                number = 0;
            }
        }
        //将栈中的操作数求和
        long sum = 0;
        for (long i : stack) {
            sum += i;
        }
        return sum;
    }
}

// Main.java

package OD340;

import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description 提取字符串中的最长表达式
 * @level 7
 * @score 100
 * @type 双指针、正则表达式、栈
 */

/**
 * 题目描述
 * 提取字符串中的最长合法简单数学表达式,字符串长度最长的,并计算表达式的值。如果没有,则返回 0
 * <p>
 * 简单数学表达式只能包含以下内容:
 * <p>
 * 0-9数字,符号+-*
 * 说明:
 * <p>
 * 所有数字,计算结果都不超过long
 * 如果有多个长度一样的,请返回第一个表达式的结果
 * 数学表达式,必须是最长的,合法的
 * 操作符不能连续出现,如 +--+1 是不合法的
 * 输入描述
 * 字符串
 * <p>
 * 输出描述
 * 表达式值
 */
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        System.out.println(getMaxMath(str));

    }

    //提取字符串中最长合法表达式并计算值(只包含两个操作数的,且第一个数带正负号),如有多个长度一样,则返回第一个
    public static long getMaxMath(String str) {
        char[] chars = str.toCharArray();
        int n = chars.length;
        //创建正则 匹配 (带正负号0个或1个) 数字1个或多个,然后是 + - * 必须1个 ,然后是 (不带正负号的数字)1个或多个
        Pattern pattern = Pattern.compile("^([+-]?\\d+)([+*-]{1}\\d+)$");
        //如果匹配不只两个操作数

        int max = 0;
        long sum = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                String sub = str.substring(i, j + 1);
                Matcher matcher = pattern.matcher(sub);
                //如果匹配成功,且长度大于当前保存的最长,则更新
                if (matcher.find() && sub.length() > max) {
                    max = sub.length();
                    sum = cal(sub);
                }
            }
        }
        return sum;
    }


    //计算合法且无括号表达式的值:如 1 + 2 * 3 返回 7
    public static long cal(String str) {
        char[] chars = str.toCharArray();
        int n = chars.length;
        //存放操作数
        Stack<Long> stack = new Stack<>();
        //初始化符号和数字
        long number = 0;
        char sign = '+';
        //默认符号为"+" 即使第一位是-1 会+0 再 -1
        for (int i = 0; i < n; i++) {
            char c = chars[i];
            //如果遇到数字,拼数字
            if (c >= '0' && c <= '9') {
                number = number * 10 + (c - '0');
            }
            //没有括号和空格等不合法行为
            //遇到符号或已经到最后一位,将数字入栈、并刷新符号和数字
            if (!Character.isDigit(c) || i == n - 1) {
                if (sign == '+') {
                    //该数字前面符号是"+"直接入栈
                    stack.push(number);
                } else if (sign == '-') {
                    //该数字前面的符号是"-",变负数后入栈
                    stack.push(-1 * number);
                } else if (sign == '*') {
                    //该数字前面是乘,弹出一个相乘后再入栈
                    stack.push(stack.pop() * number);
                }
                //刷新符号
                sign = c;
                //刷新数字
                number = 0;
            }
        }
        //将栈中的操作数求和
        long sum = 0;
        for (long i : stack) {
            sum += i;
        }
        return sum;
    }
}


// Simple.java

package OD340;

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description 简单版
 * @level 7
 * @score 100
 * @type 双指针、正则表达式、栈
 */

/**
 * 题目描述
 * 提取字符串中的最长合法简单数学表达式,字符串长度最长的,并计算表达式的值。如果没有,则返回 0
 * <p>
 * 简单数学表达式只能包含以下内容:
 * <p>
 * 0-9数字,符号+-*
 * 说明:
 * <p>
 * 所有数字,计算结果都不超过long
 * 如果有多个长度一样的,请返回第一个表达式的结果
 * 数学表达式,必须是最长的,合法的
 * 操作符不能连续出现,如 +--+1 是不合法的
 * 输入描述
 * 字符串
 * <p>
 * 输出描述
 * 表达式值
 */
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Simple {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        //简单合法表达式为只有两个操作数 如 1+1 -1+1 +1+1都是合法的
        //正则包含三部分:开头^(含有0个或1个符号的数字1个到多个) (操作符+-*) (数字1个到多个)$结尾
        Pattern pattern = Pattern.compile("^([+-]?\\d+)([+*-])(\\d+)$");
        int maxLength = 0;
        long sum = 0;
        //遍历
        for (int i = 0; i < str.length(); i++) {
            for (int j = i; j < str.length(); j++) {
                String sub = str.substring(i, j + 1);
                Matcher matcher = pattern.matcher(sub);
                //如果匹配到且长度大于当前保存的长度,则更新
                if (matcher.find() && sub.length() > maxLength) {
                    maxLength = sub.length();
                    //求解 使用matcher.group(1)和matcher.group(3)分别获取两个数字
                    long num1 = Long.parseLong(matcher.group(1));
                    long num2 = Long.parseLong(matcher.group(3));
                    //操作符
                    String sign = matcher.group(2);
                    switch (sign) {
                        case "+":
                            sum = num1 + num2;
                            break;
                        case "-":
                            sum = num1 - num2;
                            break;
                        case "*":
                            sum = num1 * num2;
                            break;
                    }

                }
            }
        }
        System.out.println(sum);
    }
}
java 复制代码
package OD341;

import java.util.HashMap;
import java.util.Scanner;

/**
 * @description 模拟目录管理功能
 * @level 6
 * @score 200
 * @url https://hydro.ac/d/HWOD2023/p/OD341
 */
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        //初始化目录树
        Tree tree = new Tree();

        //记录最后一条命令的输出 除了pwd有输出,其他都输出空
        //输出为空时要输出根目录"/" 才能百分百解法
        String command_output = "/";

        outer:
        while (sc.hasNextLine()) {
            String line = sc.nextLine();

            String[] tmp = line.split(" ");

            //命令 mkdir cd pwd
            String cmd_key = tmp[0];
            //参数
            //String cmd_val =  tmp[1];//pwd没有参数,可能会越界
            //常量在前面,防止空指针异常
            if ("pwd".equals(cmd_key)) {
                //pwd不需要参数,有参数的错误输入什么都不需要干
                if (tmp.length != 1) continue;
                //否则,就将当前命令的输出结果保存
                command_output = tree.pwd();
            } else if ("mkdir".equals(cmd_key) || "cd".equals(cmd_key)) {
                //参数只能有1个
                if (tmp.length != 2) continue;

                //目录名
                String cmd_val = tmp[1];

                //除了 cd .. 不需要检测 其他都需要检测文件名是否合法
                if (!(cmd_key.equals("cd") && cmd_val.equals(".."))) {
                    for (int i = 0; i < cmd_val.length(); i++) {
                        char c = cmd_val.charAt(i);
                        //不合法,直接跳到下一个命令
                        if (c < 'a' || c > 'z') continue outer;
                    }
                }

                //实现操作
                if ("mkdir".equals(cmd_key)) {
                    tree.mkdir(cmd_val);
                    //mkdir操作没有输出,清空当前保存的最后输出
                    command_output = "/";
                } else {
                    //cd
                    tree.cd(cmd_val);
                    //清空
                    command_output = "/";
                }
            }
        }
        //输出最后一条命令的输入,如果是mkdir cd 则没有输出
        System.out.println(command_output);
    }

    //节点 包含父目录 子目录<>
    static class TreeNode {
        //目录名
        String curDicName;
        //父目录
        TreeNode fa;
        //子目录:<子目录名,子目录对象>
        HashMap<String, TreeNode> ch;

        //构造方法 新建一个节点<节点名,父目录>
        public TreeNode(String curDicName, TreeNode fa) {
            this.curDicName = curDicName;
            this.fa = fa;
            this.ch = new HashMap<>();
        }
    }

    //目录树
    static class Tree {
        //根节点
        TreeNode root;
        //当前层
        TreeNode cur;

        //默认无参构造方法
        public Tree() {
            //根节点 视为名称为/
            this.root = new TreeNode("/", null);
            this.cur = root;
        }

        //新建目录
        public void mkdir(String dicName) {
            //如果有同名子目录,则不做任务操作
            //子目录名,子目录对象(名称+"/",该子目录的父目录)
            this.cur.ch.putIfAbsent(dicName, new TreeNode(dicName + "/", this.cur));
        }

        //进入目录
        public void cd(String dicName) {
            //cd .. 防止空指针异常
            if ("..".equals(dicName)) {
                //如果上层不为空,则进入上层
                if (this.cur.fa != null) {
                    this.cur = this.cur.fa;
                }
                //如果为空,不进行任何操作
            } else {
                //cd dicName
                //有同名子目录才进入
                if (this.cur.ch.containsKey(dicName)) {
                    //进入
                    this.cur = this.cur.ch.get(dicName);
                }
                //没有同名子目录则不做任何操作
            }
        }

        //pwd
        public String pwd() {
            StringBuilder sb = new StringBuilder();

            //从当前层遍历到root,每次插入到头部,即倒序
            TreeNode cur = this.cur;
            while (cur != null) {
                // c/ -> b/c/ -> a/b/c/ -> /a/b/c/
                sb.insert(0, cur.curDicName);
                cur = cur.fa;
            }
            return sb.toString();
        }
    }
}
相关推荐
等风来随风飘18 分钟前
华为机试HJ40统计字符
华为od·华为
小悟空GK21 分钟前
Http介绍
开发语言
JH_vision28 分钟前
Python OpenCV与霍夫变换:检测符合特定斜率范围的直线
python·目标检测
502胶水20531 分钟前
腾讯地图异步调用
开发语言·ios·swift
SwBack41 分钟前
【pearcmd】通过pearcmd.php 进行GetShell
android·开发语言·php
Lingoesforstudy42 分钟前
c#中的超时终止
开发语言·笔记·c#
Yima_Dangxian1 小时前
爬虫笔记20——票星球抢票脚本的实现
笔记·爬虫·python
**K1 小时前
C++ 智能指针使用不当导致内存泄漏问题
开发语言·c++·算法
张飞飞飞飞飞1 小时前
RKNN3588——利用推理YOLOv8推理图片
python
叫我DPT1 小时前
数据库开发:mysql基础一
python·mysql·adb·数据库开发