轉載請標明出處,原文地址: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;
}