乐言科技 笔试面试:程序填空题,编程题: 输入任意一种物质,要求输出其每种元素的数量。(Java/C++)详细注释(面试过程问详请私信)

程序填空题:

【程序说明】
应用计算机处理日常事务或者是编写程序的时候,经常需要用到带有通配符的字符串
匹配。比如:linux命令行下输入,ls*.txt 就是列出当前目录下所有的结尾是.txt
的文件。下面一段函数实现了带有$和*两种通配符的字符串的匹配功能。其中:$表示
长度大于0的数字串,*表示任意长度的字符串。

要求:按照自己对于算法的理解填写该函数的5个空白。
请注意:必须是完全匹配才能返回true,比如1.txt, a.txt可以匹配*.txt, 2.tx或者
2.txta不能匹配*.txt。函数的参数与返回值的说明请参见函数的注释。

import java.io.*;
import java.util.*;
import java.math.*;

// 功能描述: 表达式是否匹配成功, $表示长度大于 0 的数字串,*表示任意长的字符串
// 输入参数: @pRule, 以'\0'结束的字符串,表示规则;
// @pStr, 以'\0'结束的待匹配的字符串;
// 返回值:true:匹配成功; false: 匹配失败
public class Main {
	public static boolean isRegularMatching(String rule, String str) {
		int lRule = rule.length();
		int lStr = str.length();
		int iRule = 0;
		int iStr = 0;
		while (iRule < lRule && iStr < lStr) {
			switch (rule.charAt(iRule)) {//从iRule下标开始逐个匹配
				case '*': {//如果是通配符*
					iRule += 1;//规则串下标+1
					if (iRule >= lRule) {//如果规则串已走完,则匹配成功
						return true;
					} else {
						for (int i = iStr; i < lStr; i++) {
							if (str.substring(i).equals(rule.substring(iRule))) {//匹配两个字符串是否存在相同的结尾,若存在,则匹配成功
								return true;
							}
						}
					}
					break;
				}
				case '$': {//如果是数字串$
					if (!Character.isDigit(str.charAt(iStr))) {//匹配字符串该位置是否为数字,若不是就直接返回
						return false;
					}
					while ((iStr < lStr) && (str.charAt(iStr) >= '0') && (str.charAt(iStr) <= '9')) {//匹配字符串连续的数字
						iStr += 1;
					}
					iRule += 1;
					break;
				}
				default: {
					if (rule.charAt(iRule) != str.charAt(iStr)) {//若不是以上两种情况,就直接判断字符是否相同
						return false;
					}
					iRule += 1;
					iStr += 1;
					break;
				}
			}
		}
		//有一个串没走完或者都走完了
		if (iRule < lRule && iStr >= lStr) {//若规则串还没走完
			if (rule.charAt(iRule) == '*') {
				return true;
			}
		} else {//规则串走完
			return iStr>=lStr;//若lStr也匹配完了就可以返回true
		}
		return false;
	}
}

编程题:

输入任意一种物质,要求输出其每种元素的数量。
比如
输入 CaCO3,其组成分别为 Ca:1,C:1,O:3,输出 Ca1C1O3
输入 Fe2(SO4)3,其组成分别为 Fe:2,S:3,O:12,输出 Fe2S3O12
(注意:元素名称首字母大写,剩余字母都小写;括号括起来表示括号中的结构作为整体出现多少次)

个人思路:
这题算是困难题了,条件判断很多,写起来很费时间。
我用的方法是递归,大致思路是:用栈装载元素字符串,用hashmap记录元素的次数,遇见括号开一个小栈,递归返回后把小栈里的字符串倒进大栈。
在笔试过程匆忙写的,笔试后加了详细注释,还有很多可以优化的地方,欢迎大佬批评指正。

import java.io.*;
import java.util.*;
import java.math.*;

public class Main
{
	static String param;//输入串
	static HashMap<String,Integer>map;//hashmap记录元素出现次数
	public static void main(String[] args)
	{
		InputReader in = new InputReader();
		PrintWriter out=new PrintWriter(new BufferedOutputStream(System.out));
		//在下方输入代码
		StringBuilder ans=new StringBuilder();//结果串
		param=in.next();
		map=new HashMap<>();
		Deque<String>stack=new ArrayDeque<>();
		Deque<String>ansStack=method(0,stack);//最后的结果栈
		while (!ansStack.isEmpty()){
			String s=ansStack.pollLast();
			ans.append(s).append(map.get(s));//把栈里的字符和对应的次数进行拼接
		}
		out.println(ans);
		//在上方输入代码
		out.close();
	}

	static int temindex=0;//设置全局静态变量:乘数下标
	public static Deque<String> method(int index,Deque<String>big){//递归方法
		Deque<String>small=new ArrayDeque<>();//开个小栈,预装载
		for (int i = index; i < param.length(); ++i) {//for循环对字符串进行挨个校验
			if (param.charAt(i)=='('){//如果字符为‘(’,则要进入递归
				small=method(i+1, small);//由小栈装载递归结果
				int mul=param.charAt(temindex)-'0';//得出所乘次数
				for (String s:small ) {//foreach循环取出小栈里的元素
					map.put(s, map.get(s)*mul);//map重新记录元素出现次数
				}
				while (!small.isEmpty()){//把小栈里的元素倒入大栈中
					String s=small.pollLast();
					big.push(s);
				}
				i=temindex;//下标设置为‘)’数字后的索引
			}else if (Character.isUpperCase(param.charAt(i))){//如果是大写字母
				String s;
				if (i==param.length()-1||!Character.isLowerCase(param.charAt(i+1))){//如果下标是最后一位 或 第二个字符不是小写字母,则说明是单字母元素
					s= String.valueOf(param.charAt(i));
				}else {//否则是双字母元素
					s = param.substring(i, i + 2);
					i++;
				}
				map.put(s, 1);
				big.push(s);
			}else if(param.charAt(i)==')'){//如果遇到‘)’,则设置乘数下标,并将此次递归返回
				temindex=i+1;
				return big;
			}else if(Character.isDigit(param.charAt(i))&&')'!=param.charAt(i-1)){//此判断是针对 元素后直接带数字 的情况
				int mul=param.charAt(i)-'0';//计算乘数
				if (big.peek()!=null)//如果栈顶有值
					map.put(big.peek(),map.get(big.peek())*mul);//修改map中的记录值
			}
		}
		return big;
	}
}

class InputReader
{
	BufferedReader buf;
	StringTokenizer tok;
	InputReader()
	{
		buf = new BufferedReader(new InputStreamReader(System.in));
	}
	boolean hasNext()
	{
		while(tok == null || !tok.hasMoreElements())
		{
			try
			{
				tok = new StringTokenizer(buf.readLine());
			}
			catch(Exception e)
			{
				return false;
			}
		}
		return true;
	}
	String next()
	{
		if(hasNext()) return tok.nextToken();
		return null;
	}
	int nextInt()
	{
		return Integer.parseInt(next());
	}
	long nextLong()
	{
		return Long.parseLong(next());
	}
	double nextDouble()
	{
		return Double.parseDouble(next());
	}
	BigInteger nextBigInteger()
	{
		return new BigInteger(next());
	}
	BigDecimal nextBigDecimal()
	{
		return new BigDecimal(next());
	}
}

再贴一个改的C++版本

#include <bits/stdc++.h>
using namespace std;

static string param;
static unordered_map<string,int>maps;

static int temindex=0;
static deque<string> method(int index,deque<string>big){
	deque<string>samll;
	for (int i = index; i < param.length(); ++i) {
		if (param[i]=='('){
			samll= method(i+1,samll);
			int mul=param[temindex]-'0';
			while (!samll.empty()){
				string s=samll.front();
				samll.pop_front();
				maps[s]=maps[s]*mul;
				big.emplace_front(s);
			}
			i=temindex;
		} else if (isupper(param[i])){
			string s;
			if (i==param.length()-1||!islower(param[i+1])){
				s=param[i];
			} else{
				s=param.substr(i,i+2);
				++i;
			}
			maps[s]=1;
			big.emplace_front(s);
		} else if (param[i]==')'){
			temindex=i+1;
			return big;
		} else if (isdigit(param[i])&&')'!=param[i-1]){
			int mul=param[i]-'0';
			if (!big.empty()){
				maps[big.front()]=maps[big.front()]*mul;
			}
		}
	}
	return big;
}

int main()
{
	cin>>param;
	string ans="";
	deque<string>deques;
	deque<string>ansdeque= method(0,deques);
	while (!ansdeque.empty()){
		string s=ansdeque.back();
		ansdeque.pop_back();
		ans.append(s).append(to_string(maps[s]));
	}
	cout<<ans;
}

上述为乐言科技笔试题,面试过程问详请私信

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值