字符串匹配, Zenefits的面试题

昨天面了Zenefits,觉得他家考题蛮有难度,不愧是现在湾区最火startup之一。当时也没写好,这里重写一下。

String s1 = "waeginsapnaabangpisebbasepgnccccapisdnfngaabndlrjngeuiogbbegbuoecccc";

String s2 = "a+b+c-";

s2的形式是一个字母加上一个符号,正号代表有两个前面的字符,负号代表有四个,也就是说s2其实是"aabbcccc",不考虑invalid。

在s1中,找出连续或者不连续的s2,也就是说从s1中找出"aa....bb.....cccc",abc顺序不能变,但是之间可以有零个或多个字符,返回共有多少个。在上面这个例子中,有四个。


这种字符串匹配题,不难想到用DP或者recursion,与leetcode的115题结合,就可以做,但有几个地方需要注意:

1. 首先需要将s1和s2转化,s1要把关键字符提取出来,并且做变换,变成"abcabc",s2要把加减号去掉变成"abc",然后再做。

2. 为什么不把这道题直接变成"aabbccccaabbcccc"和"aabbcccc"然后再做呢,为什么要变成单个字符的形式。这道题和LC 115题不一样的地方在于,比如"aaaa"和"aa",在LC的题目中,有6种匹配,而在这道题中,只有三种,因为这道题里必须连续。也就是说如果变成"aabbccccaabbcccc"和"aabbcccc" ,其实只有四种匹配方式,但实际我们用DP或者recursion的时候"aabbccccaabbcccc"和"aabbcccc"也可以匹配,就多算了很多种情况。

3. 所以如果单纯的变成"aabbccccaabbcccc"和"aabbcccc”再做是不行的。变成"abcabc"和"abc"是正道。

4. 如果s1出现“aaabbcccc” 三个a这种情况,怎么办?那么就把s1变成“aabc”,因为"aaa"中可以选前两个a也可以选后两个a,两种匹配方式。


所以感觉这道题的难点还是需要想到转换字符串。

代码如下:

动态规划:

public static int numDistinctDP(String s1, String s2){
<span style="white-space:pre">	</span>StringBuffer sb1 = new StringBuffer();
	StringBuffer sb2 = new StringBuffer();
	HashMap<Character, Integer> map = new HashMap<Character, Integer>();
	//transform s2
	for(int i = 0; i < s2.length(); i += 2){
		char c = s2.charAt(i);
		sb2.append(c);
		map.put(c, s2.charAt(i + 1) == '+'? 1: 3);
	}
	s2 = sb2.toString();
	//transform s1
	for(int i = 0; i < s1.length() - 1; i++){
		char c = s1.charAt(i);
		if(map.containsKey(c)){
			int value = map.get(c);
			if(isValid(s1, i, value, c)){
				sb1.append(c);
			}
		}
	}
	s1 = sb1.toString();
	//start DP
	int[][] num = new int[s1.length() + 1][s2.length() + 1];
        for(int i = 0; i <= s1.length(); i++){
            num[i][0] = 1;
        }
        for(int i = 1; i <= s1.length(); i++){
            for(int j = 1; j <= s2.length(); j++){
                num[i][j] += num[i - 1][j];
                if(s1.charAt(i - 1) == s2.charAt(j - 1)){
                    num[i][j] += num[i - 1][j - 1];
                }
            }
        }
        return num[s1.length()][s2.length()];
}
<pre name="code" class="java" style="color: rgb(85, 85, 85); font-size: 11px; line-height: 21px;">private static boolean isValid(String s1, int i, int value, char c){
	if(i + value > s1.length() - 1) return false;
	for(int j = 1; j <= value; j++){
		if(s1.charAt(i + j) != c) return false;
	}
	return true;
}



 

Recursion写法:转换字符串的方式一样

</pre></p><p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Monaco;"><pre name="code" class="java">public static int numDistinctRecursion(String s1, String s2){
	StringBuffer sb1 = new StringBuffer();
	StringBuffer sb2 = new StringBuffer();
	HashMap<Character, Integer> map = new HashMap<Character, Integer>();
	//transform s2
	for(int i = 0; i < s2.length(); i += 2){
		char c = s2.charAt(i);
		sb2.append(c);
		map.put(c, s2.charAt(i + 1) == '+'? 1: 3);
	}
	s2 = sb2.toString();
	//transform s1
	for(int i = 0; i < s1.length() - 1; i++){
		char c = s1.charAt(i);
		if(map.containsKey(c)){
			int value = map.get(c);
			if(isValid(s1, i, value, c)){
				sb1.append(c);
			}
		}
	}
	s1 = sb1.toString();
	return withRecursionHelper(s1, s2);
}
	
private static boolean isValid(String s1, int i, int value, char c){
	if(i + value > s1.length() - 1) return false;
	for(int j = 1; j <= value; j++){
		if(s1.charAt(i + j) != c) return false;
	}
	return true;
}
private static int withRecursionHelper(String s1, String s2){
if(s2.length() == 0) return 1;
	if(s1.length() == 0) return 0;
	if(s1.length() < s2.length()) return 0;
	if(s1.charAt(0) != s2.charAt(0)){
		return withRecursionHelper(s1.substring(1), s2);
	}
	return withRecursionHelper(s1.substring(1), s2) + withRecursionHelper(s1.substring(1), s2.substring(1));
}

这道题还有种不需要转换字符串的recursion写法,就是本人在面试中写的,虽然当时写的一团糟啊。。。待补充。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值