转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/8035261
1、快速找出一个数组中的最大数、第二大数。
思路:如果当前元素大于最大数 max,则让第二大数等于原来的最大数 max,再把当前元素的值赋给 max。如果当前的元素大于等于第二大数secondMax的值而小于最大数max的值,则要把当前元素的值赋给 secondMax。2、试着用最小的比较次数去寻找数组中的最大值和最小值。
解法一:
扫描一次数组找出最大值;再扫描一次数组找出最小值。
比较次数2N-2
转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/8035261
解法二:
将数组中相邻的两个数分在一组, 每次比较两个相邻的数,将较大值交换至这两个数的左边,较小值放于右边。
对大者组扫描一次找出最大值,对小者组扫描一次找出最小值。
比较1.5N-2次,但需要改变数组结构
解法三:
每次比较相邻两个数,较大者与MAX比较,较小者与MIN比较,找出最大值和最小值。
方法如下:先将一对元素互相进行比较,然后把最小值跟当前最小值进行比较,把最大值跟当前最大值进行比较。因此每两个元素需要3次比较。如果n为奇数,那么比较的次数是3*(n/2)次比较。如果n为偶数,那么比较的次数是3n/2-2次比较。因此,不管是n是奇数还是偶数,比较的次数至多是3*(n/2),具体的代码如下:
3、重排问题
给定含有n个元素的整型数组a,其中包括0元素和非0元素,对数组进行排序,要求:1、排序后所有0元素在前,所有非零元素在后,且非零元素排序前后相对位置不变
2、不能使用额外存储空间
例子如下
输入 0、3、0、2、1、0、0
输出 0、0、0、0、3、2、1
分析
此排序非传统意义上的排序,因为它要求排序前后非0元素的相对位置不变,或许叫做整理会更恰当一些。我们可以从后向前遍历整个数组,遇到某个位置i上的元素是非0元素时,如果arr[k]为0,则将arr[i]赋值给arr[k],arr[i]赋值为0。实际上i是非0元素的下标,而k是0元素的下标。
4、找出绝对值最小的元素
给定一个有序整数序列(非递减序),可能包含负数,找出其中绝对值最小的元素,比如给定序列 -5、-3、-1、2、8 则返回1。分析:由于给定序列是有序的,而这又是搜索问题,所以首先想到二分搜索法,只不过这个二分法比普通的二分法稍微麻烦点,可以分为下面几种情况
如果给定的序列中所有的数都是正数,那么数组的第一个元素即是结果。
如果给定的序列中所有的数都是负数,那么数组的最后一个元素即是结果。
如果给定的序列中既有正数又有负数,那么绝对值的最小值一定出现在正数和负数的分界处。
为什么?因为对于负数序列来说,右侧的数字比左侧的数字绝对值小,如上面的-5、-3、-1,而对于整整数来说,左边的数字绝对值小,比如上面的2、8,将这个思想用于二分搜索,可先判断中间元素和两侧元素的符号,然后根据符号决定搜索区间,逐步缩小搜索区间,直到只剩下两个元素。
单独设置一个函数用来判断两个整数的符号是否相同
5、一道经典的额递归题目
函数 int func(int i ,int N);
其中i <= N,功能输出i递增到N再递减到i的整数,每行输出一个数。比如func(1,5)就是
1
2
3
4
5
4
3
2
1
要求:
1、只能有1个语句,即一个分号
2、不能使用do while until goto for if关键字,不能使用?:和逗号运算符
3、唯一能使用的库函数为printf
6、从长度为n的数组(元素互不相同)中任意选择m个数的所有组合。
DFS
7、从长度为n的数组(元素有可能相同)中任意选择m个数的所有组合。
先对数组进行排序,然后设置一个标记pre,记录前一个选择的数字,然后进行比较。
8、三色旗排序问题
一个字符串Color,其中每个元素值为‘R‘’G’‘B’三者之一,实现把数组中元素重新排列为红、绿、蓝的顺序,所有红色在前,绿色其后,蓝色最后,要如何移动次数才会最少,编写这么一个程序。
问题的解法很简单,您可以自己想像一下在移动旗子,从绳子开头进行,遇到红色往前移,遇到绿色留在中间,遇到蓝色往后移。
设有三个指针rindex、gindex、bindex,其中gindex来遍历这个数组序列
1、gindex指向G的时候,gindex++,
2、gindex指向R的时候,与rindex交换,而后gindex++,rindex++,
3、gindex指向B的时候,与bindex交换,而后,gindex不动,bindex--。
为什么,第三步,gindex指向B的时候,与bindex交换之后,gindex不动。
因为你最终的目的是为了让R、G、B成为有序排列,试想,如果第三步,gindex与bindex交换之前,万一bindex指向的是R,而gindex交换之后,gindex此刻指向的是R了,此时,gindex能动么?不能动啊,指向的是R,还得与rindex交换。
9、一个整型数组,含有N个数,将这N个数分成连续的M段,使得这M段每段的和中的最大值最小,输出最小值。(1<=N<=100000,1<=M<=N,每个数在1到10000之间) POJ 3273
解题思路:不管分成多少段,每种分法和的最大值都在N个数的最大值和N个数的和之间,所求答案也在这之间。
我们可以以此为上下界,二分M段和的最大值进行尝试。对每次二分的值,将数组扫描累加。若当前和大于二分的这个值,则段数加一,由此统计出在当前值下,N个数能够分成的最小段数。若这个段数小于或等于M,则上界变为mid-1,并记下当前mid的值。否则,下界变为mid+1。继续二分,直到退出循环。最后记录的low值即为答案。
10、一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。
能否只用一个额外数组和少量其它空间实现。
分析:最原始的方法是检查每一个数 array[i] ,看是否左边的数都小于等于它,右边的数都大于等于它。这样做的话,要找出所有这样的数,时间复杂度为O(N^2)。
其实可以有更简单的方法,我们使用额外数组,比如rightMin[],来帮我们记录原始数组array[i]右边(包括自己)的最小值。假如原始数组为: array[] = {7, 10, 2, 6, 19, 22, 32}, 那么rightMin[] = {2, 2, 2, 6, 19, 22, 32}. 也就是说,7右边的最小值为2, 2右边的最小值也是2。
有了这样一个额外数组,当我们从头开始遍历原始数组时,我们保存一个当前最大值 max, 如果当前最大值刚好等于rightMin[i], 那么这个最大值一定满足条件,还是刚才的例子。
第一个值是7,最大值也是7,因为7 不等于 2, 继续,
第二个值是10,最大值变成了10,但是10也不等于2,继续,
第三个值是2,最大值是10,但是10也不等于2,继续,
第四个值是6,最大值是10,但是10不等于6,继续,
第五个值是19,最大值变成了19,而且19也等于当前rightMin[4] = 19, 所以,满足条件。如此继续下去,后面的几个都满足。
11、整数的拆分问题
如,对于正整数n=6,可以拆分为:
6
5+1
4+2, 4+1+1
3+3, 3+2+1, 3+1+1+1
2+2+2, 2+2+1+1, 2+1+1+1+1
1+1+1+1+1+1+1
现在的问题是,对于给定的正整数n,程序输出该整数的拆分种类数(HDOJ 1028)。
DP思路:
n = n1 + n2 + n3 + n4 + .... + nk
状态表示:将n划分为k个数相加的组合方案数记为 q(n,k)。(相当于将n个苹果放入k个盘子)
状态转移:
(1)若k>n,则盘子数大于苹果数,至少有k-n个空盘子,可以将其拿掉,对组合方案数无影响。
q(n,k) = q(n,n)
(2)若k<=n,则盘子数小于等于苹果数,则分为两种情况
1.至少有一个盘子空着:q(n,k) = q(n,k-1)
2.所有盘子都不空:q(n,k) = q(n-k,k)
q(n,k) = q(n,k-1) + q(n-k,k)
方法一:DP非递归
方法二:递归思路
12、整数的拆分问题
接着上一题,输出整数的所有划分方案
13、在数组中寻找和为给定值的组合
思路:
代码
14、字符串移动
字符串为*号和26个字母、阿拉伯数字的任意组合,把*号都移动到最左侧,把其他字母和数字都移到最右侧并保持相对顺序不变,返回字符*的个数,要求时间和空间复杂度最小。
第一种方法:跟上面的重排问题是一样的
第二种方法:
时间复杂度O(N),空间复杂度O(1)
15、求数组中两个元素差的最大值
后面的元素减去前面的元素(你可以认为你在炒股票,买入价格和卖出价格就是你的盈利),要求:O(N)时间复杂度,O(1)空间复杂度
思路:首先从包含两个元素的数组开始考虑问题,当这个包含两个元素的问题解决了,那么加一个新的元素会造成什么影响?要改变哪些值?每次都添加一个元素,每次都将这些可能的改变考虑进来,这样就能做到遍历整个数组的时候,问题就解决了。
16、求数组中两个元素差的最大值
前面的元素减去后面的元素,要求:O(N)时间复杂度,O(1)空间复杂度
思路:跟上一题的思路很相近
17、输入一个正数 n,输出所有和为 n 连续正数序列。
例如输入 15,由于 1+2+3+4+5=4+5+6=7+8=15,所以输出 3 个连续序列 1-5、4-6 和 7-8。
方法一:
可以发现任意自然数序列其实是公差为1的等差数列,假设从i开始的连续k个数的和为n,即[i , i+k-1],则n=k*(2*i+k-1)/2,所以转化为一元二次方程为:k*k+(2*i-1)*k-2*n=0,解得k=(1-2*i+sqrt((2*i-1)*(2*i-1)+8*n))/2
要满足k为整数,根号里面的肯定必须是平方数,且分子为偶数,否则k就是小数。
方法二:
我们知道:
1+2 = 3;
4+5 = 9;
2+3+4 = 9。
等式的左边都是两个以上连续的自然数相加,那么是不是所有的整数都可以写成这样的形式呢?稍微考虑一下,我们发现,4和8等数不能写成这样的形式。
问题1:写一个程序,对于一个64位的正整数,输出它所有可能的连续自然数(两个以上)之和的算式。
问题2:大家在测试上面的程序的过程中,肯定会注意到有一些数字不能表达为一系列连续的自然数之和,例如32好像就找不到。那么,这样的数字有什么规律呢?能否证明你的结论?
问题3:在64位正整数范围内,子序列数目最多的数是哪一个?这个问题要用程序蛮力搜索,恐怕要运行很长时间,能够用数学知识推导出来?
问题1解答:对于任意的正整数n >= 3(1和2均不能写成连续的自然数序列之和)。假设n能够写成自然数序列[seqStart, seqEnd]之和,则有(seqEnd + seqStart)*(seqEnd - seqStart + 1) = 2*n。考虑左式是两个整数之积,想到对右边的2*n进行因数分解,不妨假定2*n = minFactor * maxFactor,则有
seqEnd + seqStart = maxFactor (1)
seqEnd - seqStart = minFactor-1 (2)
解方程组(1)(2)得:
seqStart = (maxFactor - minFactor + 1) / 2
seqEnd = (maxFactor + minFactor - 1) / 2
因为maxFactor - minFactor与maxFactor + minFactor有相同的奇偶性,因此只需要判断maxFactor + minFactor的奇偶性即可,如果maxFactor + minFactor为奇数,那么seqStart和seqEnd不是分数,是整数,即这个序列存在。下面是代码:
转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/8035261
分析:
这个问题是google的面试题。由于一个字符串有很多种二叉表示法,貌似很难判断两个字符串是否可以做这样的变换。
对付复杂问题的方法是从简单的特例来思考,从而找出规律。
先考察简单情况:
字符串长度为1:很明显,两个字符串必须完全相同才可以。
字符串长度为2:当s1="ab", s2只有"ab"或者"ba"才可以。
对于任意长度的字符串,我们可以把字符串s1分为a1,b1两个部分,s2分为a2,b2两个部分,满足((a1~a2) && (b1~b2))或者 ((a1~b2) && (a1~b2))
如此,我们找到了解决问题的思路。首先我们尝试用递归来写。
解法一(递归)
两个字符串的相似的必备条件是含有相同的字符集。简单的做法是把两个字符串的字符排序后,然后比较是否相同。
加上这个检查就可以大大的减少递归次数。
代码如下:
int l1 = s1.length();
int l2 = s2.length();
if(l1!=l2){
return false;
}
if(l1==0){
return true;
}
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
if(l1==1){
return c1[0]==c2[0];
}
Arrays.sort(c1);
Arrays.sort(c2);
for(int i=0;i<l1;++i){
if(c1[i]!=c2[i]){
return false;
}
}
boolean result = false;
for(int i=1;i<l1 && !result;++i){
String s11 = s1.substring(0,i);
String s12 = s1.substring(i);
String s21 = s2.substring(0,i);
String s22 = s2.substring(i);
result = isScramble(s11,s21) && isScramble(s12,s22);
if(!result){
String s31 = s2.substring(0,l1-i);
String s32 = s2.substring(l1-i);
result = isScramble(s11,s32) && isScramble(s12,s31);
}
}
return result;
}
解法二(动态规划)
减少重复计算的方法就是动态规划。动态规划是一种神奇的算法技术,不亲自去写,是很难完全掌握动态规划的。
这里我使用了一个三维数组boolean result[len][len][len],其中第一维为子串的长度,第二维为s1的起始索引,第三维为s2的起始索引。
result[k][i][j]表示s1[i...i+k]是否可以由s2[j...j+k]变化得来。
代码如下,非常简洁优美:
public boolean isScramble(String s1, String s2) {
int len = s1.length();
if(len!=s2.length()){
return false;
}
if(len==0){
return true;
}
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
boolean[][][] result = new boolean[len][len][len];
for(int i=0;i<len;++i){
for(int j=0;j<len;++j){
result[0][i][j] = (c1[i]==c2[j]);
}
}
for(int k=2;k<=len;++k){
for(int i=len-k;i>=0;--i){
for(int j=len-k;j>=0;--j){
boolean r = false;
for(int m=1;m<k && !r;++m){
r = (result[m-1][i][j] && result[k-m-1][i+m][j+m]) || (result[m-1][i][j+k-m] && result[k-m-1][i+m][j]);
}
result[k-1][i][j] = r;
}
}
}
return result[len-1][0][0];
}
}
posted @ 2013-05-22 22:25 小明 阅读(1944) | 评论 (0) | 编辑 收藏
分析:
因为要求结果集是升序排列,所以首先我们要对数组进行排序。
子集的长度可以从0到整个数组的长度。长度为n+1的子集可以由长度为n的子集再加上在之后的一个元素组成。
这里我使用了三个技巧
1。使用了一个index数组来记录每个子集的最大索引,这样添加新元素就很简单。
2。使用了两个变量start和end来记录上一个长度的子集在结果中的起始和终止位置。
3。去重处理使用了一个last变量记录前一次的值,它的初始值设为S[0]-1,这样就保证了和数组的任何一个元素不同。
代码如下:
public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] S) {
Arrays.sort(S);
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> indexs = new ArrayList<Integer>();
result.add(new ArrayList<Integer>());
indexs.add(-1);
int slen = S.length;
int start=0,end=0;
for(int len=1;len<=slen;++len){
int e = end;
for(int i=start;i<=end;++i){
ArrayList<Integer> ss = result.get(i);
int index = indexs.get(i).intValue();
int last = S[0]-1;
for(int j = index+1;j<slen;++j){
int v = S[j];
if(v!=last){
ArrayList<Integer> newss = new ArrayList<Integer>(ss);
newss.add(v);
result.add(newss);
indexs.add(j);
++e;
last = v;
}
}
}
start = end+1;
end = e;
}
return result;
}
}
posted @ 2013-05-21 22:50 小明 阅读(1423) | 评论 (0) | 编辑 收藏
分析:
格雷码的序列中应包含2^n个数。这个问题初看起来不容易,我们要想出一个生成方法。
对于n=2,序列是:
00,01,11,10
那对于n=3,如何利用n=2的序列呢?一个方法是,先在n=2的四个序列前加0(这其实是保持不变),然后再考虑把最高位变成1,只需要把方向反过来就可以了
000,001,011,010
100,101,111,110-> 110,111,101,100
把这两行合起来就可以得到新的序列。
想通了,写代码就很容易了。
public ArrayList<Integer> grayCode(int n) {
ArrayList<Integer> result = new ArrayList<Integer>();
result.add(0);
if(n>0){
result.add(1);
}
int mask = 1;
for(int i=2;i<=n;++i){
mask *= 2;
for(int j=result.size()-1;j>=0;--j){
int v = result.get(j).intValue();
v |= mask;
result.add(v);
}
}
return result;
}
}
posted @ 2013-05-20 21:09 小明 阅读(1520) | 评论 (0) | 编辑 收藏
解法一:(递归)
一个简单的想法,是遍历s3的每个字符,这个字符必须等于s1和s2的某个字符。如果都不相等,则返回false
我们使用3个变量i,j,k分别记录当前s1,s2,s3的字符位置。
如果s3[k] = s1[i], i向后移动一位。如果s3[k]=s2[j],j向后移动一位。
这个题目主要难在如果s1和s2的字符出现重复的时候,就有两种情况,i,j都可以向后一位。
下面的算法在这种情况使用了递归,很简单的做法。但是效率非常差,是指数复杂度的。
public boolean isInterleave(String s1, String s2, String s3) {
int l1 = s1.length();
int l2 = s2.length();
int l3 = s3.length();
if(l1+l2!=l3){
return false;
}
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
char[] c3 = s3.toCharArray();
int i=0,j=0;
for(int k=0;k<l3;++k){
char c = c3[k];
boolean m1 = i<l1 && c==c1[i];
boolean m2 = j<l2 && c==c2[j];
if(!m1 && !m2){
return false;
}
else if(m1 && m2){
String news3 = s3.substring(k+1);
return isInterleave(s1.substring(i+1),s2.substring(j),news3)
|| isInterleave(s1.substring(i),s2.substring(j+1),news3);
}
else if(m1){
++i;
}
else{
++j;
}
}
return true;
}
}
解法二:(动态规划)
为了减少重复计算,就要使用动态规划来记录中间结果。
这里我使用了一个二维数组result[i][j]来表示s1的前i个字符和s2的前j个字符是否能和s3的前i+j个字符匹配。
状态转移方程如下:
result[i,j] = (result[i-1,j] && s1[i] = s3[i+j]) || (result[i,j-1] && s2[j] = s3[i+j]);
其中0≤i≤len(s1) ,0≤j≤len(s2)
这样算法复杂度就会下降到O(l1*l2)
public boolean isInterleave(String s1, String s2, String s3) {
int l1 = s1.length();
int l2 = s2.length();
int l3 = s3.length();
if(l1+l2!=l3){
return false;
}
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
char[] c3 = s3.toCharArray();
boolean[][] result = new boolean[l1+1][l2+1];
result[0][0] = true;
for(int i=0;i<l1;++i){
if(c1[i]==c3[i]){
result[i+1][0] = true;
}
else{
break;
}
}
for(int j=0;j<l2;++j){
if(c2[j]==c3[j]){
result[0][j+1] = true;
}
else{
break;
}
}
for(int i=1;i<=l1;++i){
char ci = c1[i-1];
for(int j=1;j<=l2;++j){
char cj = c2[j-1];
char ck = c3[i+j-1];
result[i][j] = (result[i][j-1] && cj==ck) || (result[i-1][j] && ci==ck);
}
}
return result[l1][l2];
}
}
posted @ 2013-05-10 20:47 小明 阅读(1524) | 评论 (4) | 编辑 收藏
注意:
1.三元组的整数按照升序排列 a2.给出的结果中不能含有相同的三元组 阅读全文
posted @ 2013-05-01 23:13 小明 阅读(1480) | 评论 (0) | 编辑 收藏
这里的字符串的子序列指的是删除字符串的几个字符(也可以不删)而得到的新的字符串,但是不能改变字符的相对位置。
比如“ACE”是“ABCDE”的子序列,但是“AEC”就不是。
如果S=“rabbbit” T=“rabit”,有3种不同的子序列为T的构成方法,那么结果应该返回3。 阅读全文
posted @ 2013-04-26 23:33 小明 阅读(1290) | 评论 (1) | 编辑 收藏
分析:
题目不难,但是在面试时,在有限的时间内,没有bug写出,还是很考验功力的。
解决这个问题的思路是逐层扫描,上一层设置好下一层的next关系,在处理空指针的时候要格外小心。
代码如下,有注释,应该很容易看懂:
使用了三个指针:
node:当前节点
firstChild:下一层的第一个非空子节点
lastChild:下一层的最后一个待处理(未设置next)的子节点
TreeLinkNode node = root;
TreeLinkNode firstChild = null;
TreeLinkNode lastChild = null;
while(node!=null){
if(firstChild == null){ //记录第一个非空子节点
firstChild = node.left!=null?node.left:node.right;
}
//设置子节点的next关系,3种情况
if(node.left!=null && node.right!=null){
if(lastChild!=null){
lastChild.next = node.left;
}
node.left.next = node.right;
lastChild = node.right;
}
else if(node.left!=null){
if(lastChild!=null){
lastChild.next = node.left;
}
lastChild = node.left;
}
else if(node.right!=null){
if(lastChild!=null){
lastChild.next = node.right;
}
lastChild = node.right;
}
//设置下一个节点,如果本层已经遍历完毕,移到下一层的第一个子节点
if(node.next!=null){
node = node.next;
}
else{
node = firstChild;
firstChild = null;
lastChild = null;
}
}
}
posted @ 2013-04-26 11:23 小明 阅读(1245) | 评论 (0) | 编辑 收藏
分析:
这道题相比之前的两道题,难度提高了不少。
因为限制了只能交易两次,所以我们可以把n天分为两段,分别计算这两段的最大收益,就可以得到一个最大收益。穷举所有这样的分法,就可以得到全局的最大收益。
为了提高效率,这里使用动态规划,即把中间状态记录下来。使用了两个数组profits,nprofits分别记录从0..i和i..n的最大收益。
代码如下:
int days = prices.length;
if(days<2){
return 0;
}
int[] profits = new int[days];
int min = prices[0];
int max = min;
for(int i=1;i<days;++i){
int p = prices[i];
if(min>p){
max = min = p;
}
else if(max<p){
max = p;
}
int profit = max - min;
profits[i] = (profits[i-1]>profit)?profits[i-1]:profit;
}
int[] nprofits = new int[days];
nprofits[days-1] = 0;
max = min = prices[days-1];
for(int i=days-2;i>=0;--i){
int p = prices[i];
if(min>p){
min =p;
}
else if(max<p){
max = min = p;
}
int profit = max - min;
nprofits[i] = (nprofits[i+1]>profit)?nprofits[i+1]:profit;
}
int maxprofit = 0;
for(int i=0;i<days;++i){
int profit = profits[i]+nprofits[i];
if(maxprofit<profit){
maxprofit = profit;
}
}
return maxprofit;
}
posted @ 2013-04-25 22:22 小明 阅读(1286) | 评论 (0) | 编辑 收藏
分析:为了得到最大收益,必须在所有上升的曲线段的开始点买入,在最高点卖出。而在下降阶段不出手。
实现代码如下:
public int maxProfit(int[] prices) {
int len = prices.length;
if(len<2){
return 0;
}
int min=0;
int result = 0;
boolean inBuy = false;
for(int i=0;i<len-1;++i){
int p = prices[i];
int q = prices[i+1];
if(!inBuy){
if(q>p){
inBuy = true;
min=p ;
}
}
else{
if(q<p){
result += (p-min);
inBuy = false;
}
}
}
if(inBuy){
result += ((prices[len-1])-min);
}
return result;
}
}
posted @ 2013-04-19 21:50 小明 阅读(1344) | 评论 (0) | 编辑 收藏
posted @ 2013-04-19 15:03 小明 阅读(1198) | 评论 (0) | 编辑 收藏
路径可以从任意节点开始到任意节点结束。(也可以是单个节点)
比如:对于二叉树
1
/ \
2 3
和最大的路径是2->1->3,结果为6
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/ 阅读全文
posted @ 2013-04-18 21:31 小明 阅读(1233) | 评论 (0) | 编辑 收藏
1.每次只能变换一个字母
2.所有的中间单词必须存在于字典中
比如:
输入:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
那么最短的变化序列有两个
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]。
注意:
1. 所有单词的长度都是相同的
2. 所有单词都只含有小写的字母。 阅读全文
posted @ 2013-04-18 17:32 小明 阅读(1040) | 评论 (0) | 编辑 收藏
public class Solution {
public void merge(int A[], int m, int B[], int n) {
//write your code here }
}
注意:
假定A有足够的额外的容量储存B的内容,m和n分别为A和B的初始化元素的个数。要求算法复杂度在O(m+n)。 阅读全文
posted @ 2013-04-18 13:44 小明 阅读(990) | 评论 (0) | 编辑 收藏
1.每次只能变换一个字母
2.所有的中间单词必须存在于字典中
比如:
输入:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
那么最短的变化序列是"hit" -> "hot" -> "dot" -> "dog" -> "cog",所以返回长度是5。
注意:
1. 如果找不到这样的序列,返回0
2. 所有单词的长度都是相同的
3. 所有单词都只含有小写的字母。 阅读全文
posted @ 2013-04-18 12:46 小明 阅读(939) | 评论 (0) | 编辑 收藏
比如如果从根节点到叶节点的路径是1-2-3,那么这代表了123这个数字。
求出所有这样从根节点到叶节点的数字之和。
比如,对于二叉树
1
/ \
2 3
一共有两条路径1->2和1->3,那么求和的结果就是12+13=25
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int sumNumbers(TreeNode root) {
//write c 阅读全文
posted @ 2013-04-16 11:37 小明 阅读(1226) | 评论 (1) | 编辑 收藏
例子-输入:
X X X X
X O O X
X X O X
X O X X
应该输出:
X X X X
X X X X
X X X X
X O X X
public void solve(char[][] board) {
} 阅读全文
posted @ 2013-04-15 18:17 小明 阅读(1148) | 评论 (2) | 编辑 收藏
要求返回所有可能的分割。
比如,对于字符串s="aab",
返回:
[
["aa","b"],
["a","a","b"]
]
阅读全文
posted @ 2013-04-15 13:52 小明 阅读(1112) | 评论 (0) | 编辑 收藏
public class Solution {
public int[] plusOne(int[] digits) {
}
} 阅读全文
posted @ 2013-04-15 11:22 小明 阅读(1042) | 评论 (3) | 编辑 收藏
计算和返回x的平方根。 阅读全文
posted @ 2013-04-15 10:19 小明 阅读(1083) | 评论 (0) | 编辑 收藏
比如对于数组[100, 4, 200, 1, 3, 2],其中最长序列为[1,2,3,4],所以应该返回4
public class Solution {
public int longestConsecutive(int[] num) {
//write your code here
}
} 阅读全文
posted @ 2013-04-12 15:58 小明 阅读(1238) | 评论 (7) | 编辑 收藏
求最少的分割次数。 阅读全文
posted @ 2013-04-11 11:24 小明 阅读(1449) | 评论 (2) | 编辑 收藏
================================================================我的代码=============
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MatchMaker {
enum GENDER{MALE,FEMALE};
//"NAME G D X X X X X X X X X X"
private static class Member{
String name;
GENDER gender;
GENDER mate;
String[] answers;
int index;
int matched = 0;
}
String[] getBestMatches(String[] members, String currentUser, int sf){
List<Member> allMembers = new ArrayList<Member>();
Member cu = null;
for(int i=0;i<members.length;++i){
String m = members[i];
String[] c = m.split(" ");
Member mem = new Member();
mem.name= c[0];
mem.gender = c[1].equals("M")?GENDER.MALE:GENDER.FEMALE;
mem.mate = c[2].equals("M")?GENDER.MALE:GENDER.FEMALE;
mem.index = i;
mem.matched = 0;
String[] answers = mem.answers = new String[c.length-3];
for(int j=3;j<c.length;++j){
answers[j-3] = c[j];
}
allMembers.add(mem);
if(c[0].equals(currentUser)){
cu = mem;
}
}
List<Member> matched = new ArrayList<Member>();
if(cu!=null){
for(Member mem:allMembers){
if(mem!=cu && mem.gender==cu.mate){
for(int i=0;i<mem.answers.length;++i){
if(mem.answers[i].equals(cu.answers[i])){
++mem.matched;
}
}
if(mem.matched>=sf){
matched.add(mem);
}
}
}
Collections.sort(matched, new Comparator<Member>(){
public int compare(Member ma, Member mb) {
if(ma.matched!=mb.matched){
return mb.matched - ma.matched;
}
return ma.index-mb.index;
}
});
String[] result = new String[matched.size()];
for(int i=0;i<result.length;++i){
result[i] = matched.get(i).name;
}
return result;
}
return new String[0];
}
}
posted @ 2013-04-02 14:04 小明 阅读(62) | 评论 (0) | 编辑 收藏
---Question---
1.What is the output of the following program?
public class Foo {
public static void main(String[] args){
Map<byte[], String> m = new HashMap<byte[], String>();
byte[] key = "abcd".getBytes();
m.put(key, "abcd");
System.out.println(m.containsKey(key));
System.out.println(m.containsKey("abcd"));
System.out.println(m.containsKey("abcd".getBytes()));
}
}
a) true,true,false b)true,false,false c)true,true,true d) false,false,false e)Program throws an exception
2. What is the proper string filled in the following program?
Public class Foo {
public static void main(String[] args) {
String s=”1\\2\\3\\4”;
//split the string with “\”
String []result = s.split(“____”);
for(String r:result){
System.out.println(r);
}
}
}
a) \ b) \\ c) \\\ d)\\\\ e)\\\\\
3. What is the output of the following program?
public class Foo {
public static void main(String[] args) {
char[] c = new char[] { '1' };
String s = new String(c);
System.out.println("abcd" + c);
System.out.println("abcd" + s);
}
}
a) Compile error b)abcd1,abcd1 c) abcd49,abcd1 d) Program throws an exception e)none of above
4. Which class is threading safe which one object can be used between multi-threads without extra synchronized?
a) Vector b) HashMap c) ArrayList d)StringBuilder e)HashSet
5. What is the output of the following program?
public class Foo {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[]{(byte)0x0,(byte)0x1,(byte)0x2};
baos.write(b);
baos.write(0x0102);
byte[] result = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(result);
System.out.println(bais.available());
}
}
a) 0 b) 1 c)4 d) 5 e) Program throws an exception
6. What is return value of function “calc”?
public class Foo {
public static int calc() throws IOException{
int ret = 0;
try{
++ret;
throw new IOException("try");
}
catch(IOException ioe){
--ret;
return ret;
}
finally{
++ret;
return ret;
}
}
}
a) 0 b) 1 c)2 d)3 e) throws an exception
7. What is the output of the following program?
public class Foo {
public static class Value {
private int value;
public int get(){
return value;
}
public void set(int v){
value = v;
}
}
public static class Values implements Iterable<Value>{
public Values(int capacity){
this.capacity = capacity;
}
int count =1 ;
int capacity;
Value v = new Value();
public Iterator<Value> iterator() {
return new Iterator<Value>(){
public boolean hasNext() {
return count<=capacity;
}
public Value next() {
v.set(count++);
return v;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
public static void main(String[] args) {
Values vs = new Values(10);
Value result = null;
for(Value v:vs){
if(result == null){
result = v;
}
else{
result.set(result.get()+v.get());
}
}
System.out.println(result.get());
}
}
a) 20 b)40 c)45 d)55 e)throws NullpointerException
8. If add keyword “final” before a class member function, it means:
a) The method can’t access the non-final member variable.
b) The method can’t modify the member variable.
c) The method can’t be override by subclass.
d) The method is a thread-safe function.
e) The method can’t be accessed by other non-final function.
9. About Java memory and garbage collector, which statement is correct?
a) Moving variable from locale to class will make GC more effectively.
b) When Full GC is executing, all the user threads will be paused.
c) If object A contains a reference of object B and object B contains a reference of object A, the two objects can’t be reclaimed by GC.
d) When a thread exits, all objects which created by that thread will be reclaimed
e) It is recommended that calling “System.gc()” to control the memory usage.
10. About Java classpath and classloader, which statement is NOT correct?
a) User can specify the classpath by using the option “-cp” in Java command line.
b) If user doesn’t specify classpath, the JVM search the class from the current folder by default.
c) A JVM can load two different versions of a library.
d) To define customized class loader, it is possible to load class from internet at runtime.
11. Which data structure has best performance when remove an element from it?
a) Vector b)ArrayList c)LinkedList d)HashMap e)HashSet
12. Which is the correct way to convert bytes from charset “gb2312” to “utf-8”?
byte[] src , dst;
a) dst = new String(src,”utf-8”).getBytes(“gb2312”);
b) dst = new String(src,”gb2312”).getBytes(“utf-8”);
c) dst = new String(src,”utf-16”).getBytes();
d) dst = new String(src).getBytes();
e) None of above.
posted @ 2012-11-07 09:46 小明 阅读(1711) | 评论 (3) | 编辑 收藏
posted @ 2012-03-22 17:32 小明 阅读(1842) | 评论 (0) | 编辑 收藏
先看看ReadOptions有哪些参数可以指定:
struct ReadOptions {
// 是否检查checksum
// Default: false
bool verify_checksums;
// 是否将此次结果放入cache
// Default: true
bool fill_cache;
//是否指定snapshot,否则读取当前版本
// Default: NULL
const Snapshot* snapshot;
ReadOptions()
: verify_checksums(false),
fill_cache(true),
snapshot(NULL) {
}
};
下面看看读取的详细过程:
查询memtable=>查询previous memtable(imm_)=>查询文件(缓冲)
const Slice& key,
std::string* value) {
Status s;
MutexLock l(&mutex_);
SequenceNumber snapshot;
//设置snapshot
if (options.snapshot != NULL) {
snapshot = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
} else {
snapshot = versions_->LastSequence();
}
MemTable* mem = mem_;
MemTable* imm = imm_;
Version* current = versions_->current();
mem->Ref();
if (imm != NULL) imm->Ref();
current->Ref();
bool have_stat_update = false;
Version::GetStats stats;
// Unlock while reading from files and memtables
{
mutex_.Unlock();
LookupKey lkey(key, snapshot);
//先查询memtable
if (mem->Get(lkey, value, &s)) {
// Done
} else if (imm != NULL && imm->Get(lkey, value, &s)) { //然后查询previous memtable:imm_
// Done
} else {
//从文件中读取
s = current->Get(options, lkey, value, &stats);
have_stat_update = true;
}
mutex_.Lock();
}
//是否有文件需要被compaction,参见allowed_seek
if (have_stat_update && current->UpdateStats(stats)) {
MaybeScheduleCompaction();
}
mem->Unref();
if (imm != NULL) imm->Unref();
current->Unref();
return s;
}
重点来看看从version中读取:
const LookupKey& k,
std::string* value,
GetStats* stats) {
Slice ikey = k.internal_key();
Slice user_key = k.user_key();
const Comparator* ucmp = vset_->icmp_.user_comparator();
Status s;
stats->seek_file = NULL;
stats->seek_file_level = -1;
FileMetaData* last_file_read = NULL;
int last_file_read_level = -1;
//从level0向高层查找,如果再低级level中查到,则不再查询
std::vector<FileMetaData*> tmp;
FileMetaData* tmp2;
for (int level = 0; level < config::kNumLevels; level++) {
size_t num_files = files_[level].size();
//本层文件数为空,则返回
if (num_files == 0) continue;
// Get the list of files to search in this level
FileMetaData* const* files = &files_[level][0];
if (level == 0) {
//level0特殊处理,因为key是重叠,所有符合条件的文件必须被查找
tmp.reserve(num_files);
for (uint32_t i = 0; i < num_files; i++) {
FileMetaData* f = files[i];
if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
ucmp->Compare(user_key, f->largest.user_key()) <= 0) {
tmp.push_back(f);
}
}
if (tmp.empty()) continue;
std::sort(tmp.begin(), tmp.end(), NewestFirst);
files = &tmp[0];
num_files = tmp.size();
} else {
// 二分法查找,某个key只可能属于一个文件
uint32_t index = FindFile(vset_->icmp_, files_[level], ikey);
//没有查到
if (index >= num_files) {
files = NULL;
num_files = 0;
} else {
tmp2 = files[index];
if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) {
// All of "tmp2" is past any data for user_key
files = NULL;
num_files = 0;
} else {
files = &tmp2;
num_files = 1;
}
}
}
for (uint32_t i = 0; i < num_files; ++i) { //遍历本层符合条件的文件
if (last_file_read != NULL && stats->seek_file == NULL) {
//seek_file只记录第一个
stats->seek_file = last_file_read;
stats->seek_file_level = last_file_read_level;
}
FileMetaData* f = files[i];
last_file_read = f;
last_file_read_level = level;
//从table cache中读取
Iterator* iter = vset_->table_cache_->NewIterator(
options,
f->number,
f->file_size);
iter->Seek(ikey);
const bool done = GetValue(ucmp, iter, user_key, value, &s);
if (!iter->status().ok()) { //查找到
s = iter->status();
delete iter;
return s;
} else {
delete iter;
if (done) {
return s;
}
}
}
}
return Status::NotFound(Slice()); // Use an empty error message for speed
}
继续跟踪:TableCache
uint64_t file_number,
uint64_t file_size,
Table** tableptr) {
if (tableptr != NULL) {
*tableptr = NULL;
}
char buf[sizeof(file_number)];
EncodeFixed64(buf, file_number);
Slice key(buf, sizeof(buf));
//从LRU cache中查找
Cache::Handle* handle = cache_->Lookup(key);
if (handle == NULL) {
/加载文件
std::string fname = TableFileName(dbname_, file_number);
RandomAccessFile* file = NULL;
Table* table = NULL;
Status s = env_->NewRandomAccessFile(fname, &file);
if (s.ok()) {
s = Table::Open(*options_, file, file_size, &table);
}
if (!s.ok()) {
assert(table == NULL);
delete file;
// We do not cache error results so that if the error is transient,
// or somebody repairs the file, we recover automatically.
return NewErrorIterator(s);
}
//插入Cache
TableAndFile* tf = new TableAndFile;
tf->file = file;
tf->table = table;
handle = cache_->Insert(key, tf, 1, &DeleteEntry);
}
Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
//从Table对象中生成iterator
Iterator* result = table->NewIterator(options);
result->RegisterCleanup(&UnrefEntry, cache_, handle);
if (tableptr != NULL) {
*tableptr = table;
}
return result;
}
posted @ 2012-03-21 17:30 小明 阅读(1352) | 评论 (0) | 编辑 收藏
影响写性能的因素有:
1. write_buffer_size
2. kL0_SlowdownWritesTrigger and kL0_StopWritesTrigger.提高这两个值,能够增加写的性能,但是降低读的性能
看看WriteOptions有哪些参数可以指定
//设置sync=true,leveldb会调用fsync(),这会降低插入性能
//同时会增加数据的安全性
//Default: false
bool sync;
WriteOptions()
: sync(false) {
}
};
首先把Key,value转成WriteBatch
WriteBatch batch;
batch.Put(key, value);
return Write(opt, &batch);
}
接下来就是真正的插入了
这里使用了两把锁,主要是想提高并发能力,减少上锁的时间。
首先是检查是否可写,然后append log,最后是插入memtable
<db/dbimpl.cc>
Status status;
//加锁
MutexLock l(&mutex_);
LoggerId self;
//拿到写log的权利
AcquireLoggingResponsibility(&self);
//检查是否可写
status = MakeRoomForWrite(false); // May temporarily release lock and wait
uint64_t last_sequence = versions_->LastSequence();
if (status.ok()) {
WriteBatchInternal::SetSequence(updates, last_sequence + 1);
last_sequence += WriteBatchInternal::Count(updates);
// Add to log and apply to memtable. We can release the lock during
// this phase since the "logger_" flag protects against concurrent
// loggers and concurrent writes into mem_.
{
assert(logger_ == &self);
mutex_.Unlock();
//IO操作:写入LOG
status = log_->AddRecord(WriteBatchInternal::Contents(updates));
if (status.ok() && options.sync) {
status = logfile_->Sync();
}
//插入memtable
if (status.ok()) {
status = WriteBatchInternal::InsertInto(updates, mem_);
}
mutex_.Lock();
assert(logger_ == &self);
}
//设置新的seqence number
versions_->SetLastSequence(last_sequence);
}
//释放写LOG锁
ReleaseLoggingResponsibility(&self);
return status;
}
写流量控制:
<db/dbimpl.cc>
mutex_.AssertHeld();
assert(logger_ != NULL);
bool allow_delay = !force;
Status s;
while (true) {
if (!bg_error_.ok()) {
// Yield previous error
s = bg_error_;
break;
} else if (
allow_delay &&
versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) {
mutex_.Unlock();
//如果level0的文件大于kL0_SlowdownWritesTrigger阈值,则sleep 1s,这样给compaction更多的CPU
env_->SleepForMicroseconds(1000);
allow_delay = false; // Do not delay a single write more than once
mutex_.Lock();
} else if (!force &&
(mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {
//可写
break;
} else if (imm_ != NULL) {
// imm_:之前的memtable 没有被compaction,需要等待
bg_cv_.Wait();
} else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {
// level0文件个数大于kL0_StopWritesTrigger,需要等待
Log(options_.info_log, "waiting\n");
bg_cv_.Wait();
} else {
//生成新的额memtable和logfile,把当前memtable传给imm_
assert(versions_->PrevLogNumber() == 0);
uint64_t new_log_number = versions_->NewFileNumber();
WritableFile* lfile = NULL;
s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);
if (!s.ok()) {
break;
}
delete log_;
delete logfile_;
logfile_ = lfile;
logfile_number_ = new_log_number;
log_ = new log::Writer(lfile);
imm_ = mem_;
has_imm_.Release_Store(imm_);
mem_ = new MemTable(internal_comparator_);
mem_->Ref();
force = false; // Do not force another compaction if have room
}
}
return s;
}