第 218 场周赛阿里巴巴专场(只做出了前三道)设计 Goal 解析器+K 和数对的最大数目+连接连续二进制数字

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/goal-parser-interpretation
声明:如果我侵犯了任何人的权利,请联系我,我会删除
欢迎高手来喷我

大神的代码来自 argnote,此次周赛中以java取得前五的成绩(第四),厉害了!!!!!!!!!

5617. 设计 Goal 解析器

请你设计一个可以解释字符串 command 的 Goal 解析器 。command 由 “G”、"()" 和/或 "
(al)" 按某种顺序组成。Goal 解析器会将 “G” 解释为字符串 “G”、"()" 解释为字符串 “o” ,"(al)" 解释为字符串 “al” 。然后,按原顺序将经解释得到的字符串连接成一个字符串。

给你字符串 command ,返回 Goal 解析器 对 command 的解释结果。

示例 1:
输入:command = “G()(al)”
输出:“Goal”
解释:Goal 解析器解释命令的步骤如下所示:
G -> G
() -> o
(al) -> al
最后连接得到的结果是 “Goal”

本人的代码直接用的遍历模拟:
class Solution {
    public String interpret(String command) {
        char[] chs = command.toCharArray();
        int len = chs.length;
        int i=0;
        StringBuffer sb = new StringBuffer();
        while(i<len){
          if(chs[i]=='('){
              if(chs[i+1]=='a'){
                  sb.append("al");i++;i++;i++;i++;
              }else if(chs[i+1]==')'){
                  sb.append('o');i++;
              }
          }else if(chs[i]=='G'){
              sb.append('G');i++;
          }else i++;
        }  
        return sb.toString(); 
    }
}
参考大神的代码,直接用replaceAll()
	public String interpret(String command) {
		return command.replaceAll("\\(\\)", "o").replaceAll("\\(al\\)", "al");
	}

这里贴一些replaceAll的用法:

  • 替换字符串中的数字:
    String str = “ab123sdab4543das756as876asd”;
    str = str.replaceAll("\d+", “#num#”); //"\d+",任意多个数字字符
    输出:ab#num#sdab#num#das#num#as#num#asd
    或者:
    str = str.replaceAll("[0-9]+", “#num#”);是一样的结果
  • 替换任意的非特殊字符串:
    String regex = “(wqnmlgb|shuai|mei|rnmb|com|db|djb)”;
    String message = “wqnmlgb!你怎么这么mei!com!你真shuai”;
    message = message.replaceAll(regex, “***”);
    输出:***!你怎么这么***!***!你真***
  • 替换.点符号
    String classFile = “com.jd.beijing”. replaceAll("\.", “") + “MyClass.class”;
    输出:com
    jdbeijingMyClass.class
    如果不加转义字符:
    String classFile = “com.jd.beijing”. replaceAll(".", "
    ”) + “MyClass.class”;
    输出:**************MyClass.class
  • 替换 \ 字符
    String str1=“aa\bbb”, str2=“aa’bbb”;
    System.out.println(str1); //输出:aa\bbb
    str1 = str1.replaceAll("\\", “-”);
    System.out.println(str2); //输出:aa-bbb
    str2 = str2.replaceAll("’", “\\”);
    System.out.println(str2); //输出:aa\bbb
    String 的 replaceAll() 方法,实际是采用正则表达式的规则去匹配的,\\ ,java解析为\交给正则表达式, 正则表达式再经过一次转换,把\转换成为\
5618. K 和数对的最大数目

给你一个整数数组 nums 和一个整数 k 。
每一步操作中,你需要从数组中选出和为 k 的两个整数,并将它们移出数组。
返回你可以对数组执行的最大操作数。

示例 1:
输入:nums = [1,2,3,4], k = 5
输出:2
解释:开始时 nums = [1,2,3,4]:

  • 移出 1 和 4 ,之后 nums = [2,3]
  • 移出 2 和 3 ,之后 nums = []
    不再有和为 5 的数对,因此最多执行 2 次操作。
    示例 2:

输入:nums = [3,1,3,4,3], k = 6
输出:1
解释:开始时 nums = [3,1,3,4,3]:

  • 移出前两个 3 ,之后nums = [1,4,3]
    不再有和为 6 的数对,因此最多执行 1 次操作。

提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
1 <= k <= 109

我自己用的模拟,

用Map<Integer, List> 来记录每个数字出现的下标list,然后遍历数组nums,找到匹配的就在list中删除,注意一下两个数字相等且相加等于K的情况,这时候只能操作一个list

public int maxOperations(int[] nums, int k) {
        Map<Integer, List<Integer>> map = new HashMap<>();
        //将下标存进对应的list中
        for(int i=0;i<nums.length;++i){
            if(!map.containsKey(nums[i])){
                map.put(nums[i],new ArrayList<Integer>());
            }
            map.get(nums[i]).add(i);
        } 
        int ret = 0;
        for(int i=0;i<nums.length;++i){
            int t = k-nums[i];
            List<Integer> list = map.get(nums[i]);
            //如果 k-nums[i] = nums[i],只能操作一个list两次
            if(t==nums[i]){
                if(list.size()>=2){
                    ret ++;
                    list.remove(list.size()-1);
                    list.remove(list.size()-1);  
                } 
            }else{
            //否则就操作两个list,每个list都减去1
                if(list.size()>0){ 
                    if(map.containsKey(t)){
                        List<Integer> tmp = map.get(t);
                        if(tmp.size()>0){
                            ret ++;
                            tmp.remove(tmp.size()-1);
                            list.remove(list.size()-1);
                        }
                    }
                }
            } 
        }
        return ret;
    }
大神的代码:

应该是相似的思路,不过没有记录下标,而是记录的数字出现的个数,

  • k - num 和num不相等的话,直接把count+(num,k-num出现的次数的最小值)
  • k - num 和 num相等的话,由于数成对出现,所以要count + (num出现的次数 /2),比如num=3出现的次数为4,k=6,那么k-num=num,cout + 4/2,因为(3,3),(3,3)成对
  • 最后已经计数过的 num和k-num要从mao里面去掉
public int maxOperations(int[] nums, int k) {
		//用map记录数字出现的个数
		HashMap<Integer, Integer> map = new HashMap<>();
		for (int num : nums) {
			map.put(num, map.getOrDefault(num, 0) + 1);
		}
		int count = 0;
		for (int num : nums) {
			if (map.containsKey(num) && map.containsKey(k - num)) {
				count += Math.min(map.get(num), map.get(k - num)) / (num == k - num ? 2 : 1);
				map.remove(num);
				map.remove(k - num);
			}
		}
		return count;
	}
5620. 连接连续二进制数字

给你一个整数 n ,请你将 1 到 n 的二进制表示连接起来,并返回连接结果对应的 十进制 数字对 10^9 + 7 取余的结果。

示例 1:
输入:n = 1
输出:1
解释:二进制的 “1” 对应着十进制的 1 。

实例 2:
输入:n = 3
输出:27
解释:二进制下,1,2 和 3 分别对应 “1” ,“10” 和 “11” 。
将它们依次连接,我们得到 “11011” ,对应着十进制的 27 。

示例 3:
输入:n = 12
输出:505379714
解释:连接结果为 “1101110010111011110001001101010111100” 。
对应的十进制数字为 118505380540 。
对 109 + 7 取余后,结果为 505379714 。

提示:
1 <= n <= 10^5

我的思路:

                            以3为例:n=1,2,3,
                             也就是1, 10,11,
             分别拼接起来就是1,110,11011,
可以看出n=2时,n=1往左平移两位再加2,n=3时,n=2往左平移三位再加3,
由此看出n=N时,n=N-1需要往左平移N的(二进制的位数)位再加N…

public int concatenatedBinary(int n) {
        //int bitcount = bitcount(n);
        //System.out.println(bitcount);
        //这里偷懒了,用long来定义ret,避免平移是产生溢出,
        long ret = 1L;
        for(int i=2;i<=n;++i){
            int bitcount = bitcount(i);
            ret = (ret << bitcount) + i;
            ret = ret % 1000000007;
        }
        return (int)ret;
    }
    //n的二进制有多少位,比如n=3有3位,n=12时有4位
    public int bitcount(int n){
        int ret = 1;
        while(n / 2 != 0){
            ret++;
            n /= 2;
        }
        return ret;
    }
大神的代码 直接用的位运算,,,,位运算,,,位,,,

我还是啃了啃,妈呀,真香!!!!所以我加了点//解释

public int concatenatedBinary(int n) {
		//用long是为了避免在移位的时候产生溢出的麻烦
		long size = 0, result = 0;
		for (int i = 1; i <= n; i++) {
			//这里的(i & (i - 1)是为了计算左移的位数
			//遍历到10时,因为之前是1,size=1,所以要size+1
			//遍历到100时,之前是01,11,size=2,所以size+1
			//1到10,位数加一, 11到100位数加一, 111到1000位数加一。。。。
			if ((i & (i - 1)) == 0) {
				size += 1;
			}
			//size计算出来之后,就是result左移size位,然后加i,这里的 | 按位或的操作相当于加法了,比如,3(11)向左移动2位后,是1100,再和2(10)或,就成了1110,相当于加法了
			result = ((result << size) | i) % 1000000007;
		}
		return (int) result;
	}
5619. 最小不兼容性(我没有做出来,题解也看不懂,只做了题目的搬运工)

给你一个整数数组 nums​​​ 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。

一个子集的 不兼容性 是该子集里面最大值和最小值的差。

请你返回将数组分成 k 个子集后,各子集 不兼容性 的 和 的 最小值 ,如果无法分成分成 k 个子集,返回 -1 。

子集的定义是数组中一些数字的集合,对数字顺序没有要求。

示例 1:
输入:nums = [1,2,1,4], k = 2
输出:4
解释:最优的分配是 [1,2] 和 [1,4] 。
不兼容性和为 (2-1) + (4-1) = 4 。
注意到 [1,1] 和 [2,4] 可以得到更小的和,但是第一个集合有 2 个相同的元素,所以不可行

示例 2:
输入:nums = [6,3,8,1,3,1,2,2], k = 4
输出:6
解释:最优的子集分配为 [1,2],[2,3],[6,8] 和 [1,3] 。
不兼容性和为 (2-1) + (3-2) + (8-6) + (3-1) = 6 。

示例 3:
输入:nums = [5,3,3,6,3,3], k = 3
输出:-1
解释:没办法将这些数字分配到 3 个子集且满足每个子集里没有相同数字。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值