字符串匹配, Zenefits的面试题

来源:互联网 发布:中国旅游服务贸易数据 编辑:程序博客网 时间:2024/05/18 13:08

昨天面了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 s2for(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 s1for(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 DPint[][] 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 s2for(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 s1for(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
原创粉丝点击