原子的数目 递归(困难)

18 篇文章 0 订阅
10 篇文章 0 订阅

题目:给定一个化学式formula(作为字符串),返回每种原子的数量。

原子总是以一个大写字母开始,接着跟随0个或任意个小写字母,表示原子的名字。

如果数量大于 1,原子后会跟着数字表示原子的数量。如果数量等于 1 则不会跟数字。例如,H2O 和 H2O2 是可行的,但 H1O2 这个表达是不可行的。

两个化学式连在一起是新的化学式。例如 H2O2He3Mg4 也是化学式。

一个括号中的化学式和数字(可选择性添加)也是化学式。例如 (H2O2) 和 (H2O2)3 是化学式。

给定一个化学式,输出所有原子的数量。格式为:第一个(按字典序)原子的名子,跟着它的数量(如果数量大于 1),然后是第二个原子的名字(按字典序),跟着它的数量(如果数量大于 1),以此类推。

示例 1:

输入:
formula = “H2O”
输出: “H2O”
解释:
原子的数量是 {‘H’: 2, ‘O’: 1}。

示例 2:

输入:
formula = “Mg(OH)2”
输出: “H2MgO2”
解释:
原子的数量是 {‘H’: 2, ‘Mg’: 1, ‘O’: 2}。

示例 3:

输入:
formula = “K4(ON(SO3)2)2”
输出: “K4N2O14S4”
解释:
原子的数量是 {‘K’: 4, ‘N’: 2, ‘O’: 14, ‘S’: 4}。

注意:

所有原子的第一个字母为大写,剩余字母都是小写。
formula的长度在[1, 1000]之间。
formula只包含字母、数字和圆括号,并且题目中给定的是合法的化学式。

来源:力扣(LeetCode)

思路
我们用一个整型数 n 来表示我们正在遍历的位置
辅助结构:HashMap
递归中分三类
1、当我们碰到左括号时就递归解决左括号即其对应的有括号内的内容。
2、碰到右括号便返回下标+1。
3、碰到元素,则将元素及其数量加入哈希表中。

代码以及详解如下:

public String countOfAtoms(String formula) {
		Map<String,Integer> map = new HashMap<String,Integer>();
        helper(formula,0,map);
        List<String> list = new ArrayList<String>();
        for(String name:map.keySet()) {
        	list.add(name);
        }
        Collections.sort(list);
        StringBuffer sb = new StringBuffer();
        for(String name:list) {
        	sb.append(name);
        	int num = map.get(name);
        	if(num>1) {
        		sb.append(num);
        	}
        }
        return sb.substring(0,sb.length());
    }
	public int helper(String s,int n,Map<String,Integer> map) {
			int size = s.length();
			while(n<size) {
				Map<String,Integer> tempMap = new HashMap<String,Integer>();
				if(s.charAt(n) == '(') {//如果遇到左括号递归处理
					n = helper(s,n+1,tempMap);
					//递归完成之后便处理完毕该括号内部,用tempMap记录括号内部情况,返回有括号下标+1
					
					int nums = 0;
					while(n<size&&Character.isDigit(s.charAt(n))) {//有括号处是否有数字
						nums = nums*10+s.charAt(n)-'0';
						n++;
					}
					if(nums>0) {
						multiply(tempMap,nums);//如果下标大于1(即nums>0)则将里面的元素个数乘于nums
					}
					combine(map,tempMap);//合并两个map到map里
				}
				else if(s.charAt(n)==')') {
					return n+1;
				}
				else {//遇到普通元素
					int i = n;
					n++;
					while(n<size&&Character.isLowerCase(s.charAt(n))) {n++;}
					String s1 = s.substring(i,n);
					int tempNum = 0;
					while(n<size&&Character.isDigit(s.charAt(n))){
						tempNum = tempNum*10+s.charAt(n)-'0';
						n++;
					}
					if(tempNum == 0) {tempNum = 1;};
					if(map.get(s1)!=null) {
						int nn = map.get(s1);
						map.remove(s1);
						map.put(s1, nn+tempNum);
					}
					else {map.put(s1, tempNum);}
				}
			}
			return n+1;
	}
	public void multiply(Map<String,Integer> map,int nums) {//用来将map里的数据倍乘
		List<String> list = new ArrayList<String>();
		for(String name:map.keySet()) {
			list.add(name);
		}
		while(0<list.size()) {
			int num = map.get(list.get(0));
			map.remove(list.get(0));
			map.put(list.get(0), num*nums);
			list.remove(0);
		}
	}
	public void combine(Map<String,Integer> map1,Map<String,Integer> map2) {
		for(String name:map2.keySet()) {
			if(map1.get(name)!=null) {//如果map1包含map2里的name
				int tempNum = map1.get(name);
				map1.remove(name);
				map1.put(name, map2.get(name)+tempNum);
			}
			else {
				map1.put(name, map2.get(name));
			}
		}
	}

不要在意递归的过程,不要深入,只需知道递归前于递归后即可。

感悟:
编程是一件坚持下去就会越来越有意思的事情,通过这道题更让我认识到,难的东西都只是刚开始,当我们持之以恒的越过那座山,便会领略到新的风景提升到新的意境!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值