1.把二元查找樹轉變成排序的雙向鏈表
題目:
輸入一棵二元查找樹,將該二元查找樹轉換成一個排序的雙向鏈表。
要求不能創(chuàng)建任何新的結點,只調整指針的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
轉換成雙向鏈表
4=6=8=10=12=14=16。
首先我們定義的二元查找樹 節(jié)點的數據結構如下:
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
2.設計包含min函數的棧。
定義棧的數據結構,要求添加一個min函數,能夠得到棧的最小元素。
要求函數min、push以及pop的時間復雜度都是O(1)。
3.求子數組的最大和
題目:
輸入一個整形數組,數組里有正數也有負數。
數組中連續(xù)的一個或多個整數組成一個子數組,每個子數組都有一個和。
求所有子數組的和的最大值。要求時間復雜度為O(n)。
例如輸入的數組為1, -2, 3, 10, -4, 7, 2, -5,和最大的子數組為3, 10, -4, 7, 2,
因此輸出為該子數組的和18。
4.在二元樹中找出和為某一值的所有路徑
題目:輸入一個整數和一棵二元樹。
從樹的根結點開始往下訪問一直到葉結點所經過的所有結點形成一條路徑。
打印出和與輸入整數相等的所有路徑。
例如 輸入整數22和如下二元樹
10
/ \
5 12
/ \
4 7
則打印出兩條路徑:10, 12和10, 5, 7。
二元樹節(jié)點的數據結構定義為:
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};
5.查找最小的k個元素(采用小根堆 和 大根堆 來解決)
題目:輸入n個整數,輸出其中最小的k個。
例如輸入1,2,3,4,5,6,7和8這8個數字,則最小的4個數字為1,2,3和4。
public static void FindKMin(int[] sort, int k)
{
int[] heap = sort;
int rootIndex = k / 2 - 1;
while (rootIndex >= 0)
{
reheap(heap, rootIndex, k - 1);
rootIndex--;
}
for (int i = k, len=heap.Length; i < len; i++)
{
if (heap[i]<heap[0])
{
heap[0] = heap[i];
reheap(heap, 0, k - 1);
}
}
Console.WriteLine("The {0} min element =",k);
for (int i = 0; i < k; i++)
{
Console.Write(heap[i] + " ");
}
}
private static void reheap(int[] heap, int rootIndex, int lastInddex)
{
int orphan = heap[rootIndex];
bool done = false;
int leftIndex = rootIndex * 2 + 1;
while (!done && leftIndex <= lastInddex)
{
int largerIndex = leftIndex;
if (leftIndex+1 <= lastInddex)
{
int rightIndex = leftIndex + 1;
if (heap[rightIndex] > heap[leftIndex])
{
largerIndex = rightIndex;
}
}
if (orphan < heap[largerIndex])
{
heap[rootIndex] = heap[largerIndex];
rootIndex = largerIndex;
leftIndex = rootIndex * 2 + 1;
}
else
{
done = true;
}
}
heap[rootIndex] = orphan;
}
第6題
騰訊面試題:
給你10分鐘時間,根據上排給出十個數,在其下排填出對應的十個數
要求下排每個數都是先前上排那十個數在下排出現的次數。
上排的十個數如下:
【0,1,2,3,4,5,6,7,8,9】
舉一個例子,
數值: 0,1,2,3,4,5,6,7,8,9
分配: 6,2,1,0,0,0,1,0,0,0
0在下排出現了6次,1在下排出現了2次,
2在下排出現了1次,3在下排出現了0次....
以此類推..
完整代碼如下:
include<iostream>
using namespace std;
const int Len = 4;
bool isLegal(int* A,int n)
{
for(int i=0;i<n;++i)
{
int count=0;
for(int j=0;j<n;++j)
{
if(i==A[j])
++count;
}
if(A[i] != count)
return false;
}
return true;
}
void ArrayF(int* A,int n,int Sum)
{
if(!A || n < 1 || Sum < 1)//處理異常,A==NULL,n <=0,Sum<1
return ;
if( n==1 )
{
A[0]=Sum;
if(isLegal(A,Len))
{
for(int i=0;i<Len;++i)
cout<<A[i]<<' ';
cout<<endl;
}
}
else
{
for(int i=0;i<=Sum;++i)
{
A[n-1]=i;
ArrayF(A,n-1,Sum-i);
}
}
}
void main()
{
int A[20]={0};
ArrayF(A,Len,Len);
}
第7題
微軟亞院之編程判斷倆個鏈表是否相交
給出倆個單向鏈表的頭指針,比如h1,h2,判斷這倆個鏈表是否相交。
為了簡化問題,我們假設倆個鏈表均不帶環(huán)。
問題擴展:
1.如果鏈表可能有環(huán)列?
2.如果需要求出倆個鏈表相交的第一個節(jié)點列?
第8題
1.有兩個房間,一間房里有三盞燈,另一間房有控制著三盞燈的三個開關,
這兩個房間是 分割開的,從一間里不能看到另一間的情況。
現在要求受訓者分別進這兩房間一次,然后判斷出這三盞燈分別是由哪個開關控制的。
有什么辦法呢?
(先亮A燈一段時間,再關閉A燈亮B燈,進入有燈的房間,得出結論:亮著的是B燈,暗著的兩盞燈中,熱的燈是A燈,剩下的是C燈)
2.你讓一些人為你工作了七天,你要用一根金條作為報酬。金條被分成七小塊,每天給出一塊。
如果你只能將金條切割兩次,你怎樣分給這些工人?
3. ★用一種算法來顛倒一個鏈接表的順序?,F在在不用遞歸式的情況下做一遍。
a1 -> a2 ->a3
第一對:(NULL,a1) ——開始
第二對:(a1,a2)
第三對:(a2,a3)
第四對:(a3,NULL) ——完畢
//非遞歸方式翻轉
void Reverse_non_recursive(){
Node *pair1 = NULL;
Node *pair2 = head;
while (pair2 != NULL){
Node *temp = pair2->next;
pair2->next = pair1;
pair1 = pair2;
pair2 = temp;
}
head = pair1;
}
★用一種算法在一個循環(huán)的鏈接表里插入一個節(jié)點,但不得穿越鏈接表。
★用一種算法整理一個數組。你為什么選擇這種方法?
★用一種算法使通用字符串相匹配。
★顛倒一個字符串。優(yōu)化速度。優(yōu)化空間。
★顛倒一個句子中的詞的順序,比如將“我叫克麗絲”轉換為“克麗絲叫我”,
實現速度最快,移動最少。
★找到一個子字符串。優(yōu)化速度。優(yōu)化空間。
★比較兩個字符串,用O(n)時間和恒量空間。
★假設你有一個用1001個整數組成的數組,這些整數是任意排列的,但是你知道所有的整數都在1到1000(包括1000)之間。此外,除一個數字出現 兩次外,其他所有數字只出現一次。假設你只能對這個數組做一次處理,用一種算法找出重復的那個數字。如果你在運算中使用了輔助的存儲方式,那么你能找到不 用這種方式的算法嗎?
★不用乘法或加法增加8倍?,F在用同樣的方法增加7倍。
第9題
判斷整數序列是不是二元查找樹的后序遍歷結果
(思路是序列最后一個必是根節(jié)點,從前往后遍歷,比根節(jié)點小的都是其左子樹,并且位于序列的左半部分,比其大的為其右子樹,應該位于其右半部分。)
include <iostream>
using namespace std;
void test(const int data[],int start,int node,bool &flag){
if(flag&&start<node){ // 判斷條件,注意start<node
int left=start;
while(data[node]>data[left]){ //取得其左子樹
left++;
}
for(int j=left;j<node;j++){ //判斷是否為其右子樹
if(data[j]<data[node]) {flag=false; return;} //若
}
test(data,0,left-1,flag); //遞歸
test(data,left,node-1,flag);
}
}
int main(void){
bool flag=true;
int a[]={5,7,6,9,11,10,8};
test(a,0,6,flag);
if(flag) cout<<"yes"<<endl;
else cout<<"no"<<endl;
int b[]={7,4,6,5};
test(b,0,3,flag);
if(flag) cout<<"yes"<<endl;
else cout<<"no"<<endl;
system("pause");
return 0;
}
第10題
翻轉句子中單詞的順序。
題目:輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字符的順序不變。
句子中單詞以空格符隔開。為簡單起見,標點符號和普通字母一樣處理。
例如輸入“I am a student.”,則輸出“student. a am I”。
第11題
求二叉樹中節(jié)點的最大距離...
如果我們把二叉樹看成一個圖,父子節(jié)點之間的連線看成是雙向的,
我們姑且定義"距離"為兩節(jié)點之間邊的個數。
寫一個程序,
求一棵二叉樹中相距最遠的兩個節(jié)點之間的距離。
第12題
題目:求1+2+…+n,
要求不能使用乘除法、for、while、if、else、switch、case等關鍵字以及條件判斷語句(A?B:C)。
第13題:
題目:輸入一個單向鏈表,輸出該鏈表中倒數第k個結點。鏈表的倒數第0個結點為鏈表的尾指針。
鏈表結點定義如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
第14題:
題目:輸入一個已經按升序排序過的數組和一個數字,
在數組中查找兩個數,使得它們的和正好是輸入的那個數字。
要求時間復雜度是O(n)。如果有多對數字的和等于輸入的數字,輸出任意一對即可。
例如輸入數組1、2、4、7、11、15和數字15。由于4+11=15,因此輸出4和11。
第15題:
題目:輸入一顆二元查找樹,將該樹轉換為它的鏡像,
即在轉換后的二元查找樹中,左子樹的結點都大于右子樹的結點。
用遞歸和循環(huán)兩種方法完成樹的鏡像轉換。
例如輸入:
8
/ \
6 10
/\ /\
5 7 9 11
輸出:
8
/ \
10 6
/\ /\
11 9 7 5
定義二元查找樹的結點為:
struct BSTreeNode // a node in the binary search tree (BST)
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
第16題:
題目(微軟):
輸入一顆二元樹,從上往下按層打印樹的每個結點,同一層中按照從左往右的順序打印。
例如輸入
8
/ \
6 10
/ \ / \
5 7 9 11
輸出8 6 10 5 7 9 11。
第17題:
題目:在一個字符串中找到第一個只出現一次的字符。如輸入abaccdeff,則輸出b。
分析:這道題是2006年google的一道筆試題。
第18題:
題目:n個數字(0,1,…,n-1)形成一個圓圈,從數字0開始,
每次從這個圓圈中刪除第m個數字(第一個為當前數字本身,第二個為當前數字的下一個數字)。
當一個數字刪除后,從被刪除數字的下一個繼續(xù)刪除第m個數字。
求出在這個圓圈中剩下的最后一個數字。
July:我想,這個題目,不少人已經 見識過了。
第19題:
題目:定義Fibonacci數列如下:
/ 0 n=0
f(n)= 1 n=1
\ f(n-1)+f(n-2) n=2
輸入n,用最快的方法求該數列的第n項。
分析:在很多C語言教科書中講到遞歸函數的時候,都會用Fibonacci作為例子。
因此很多程序員對這道題的遞歸解法非常熟悉,但....呵呵,你知道的。。
第20題:
題目:輸入一個表示整數的字符串,把該字符串轉換成整數并輸出。
例如輸入字符串"345",則輸出整數345。
第21題
2010年中興面試題
編程求解:
輸入兩個整數 n 和 m,從數列1,2,3.......n 中 隨意取幾個數,
使其和等于 m ,要求將其中所有的可能組合列出來.
第22題:
有4張紅色的牌和4張藍色的牌,主持人先拿任意兩張,再分別在A、B、C三人額頭上貼任意兩張牌,
A、B、C三人都可以看見其余兩人額頭上的牌,看完后讓他們猜自己額頭上是什么顏色的牌,
A說不知道,B說不知道,C說不知道,然后A說知道了。
請教如何推理,A是怎么知道的。
如果用程序,又怎么實現呢?
第23題:
用最簡單,最快速的方法計算出下面這個圓形是否和正方形相交。"
3D坐標系 原點(0.0,0.0,0.0)
圓形:
半徑r = 3.0
圓心o = (., 0.0, .)
正方形:
4個角坐標;
1:(., 0.0, .)
2:(., 0.0, .)
3:(., 0.0, .)
4:(., 0.0, .)
第24題:
鏈表操作,
(1).單鏈表就地逆置,
(2)合并鏈表
第25題:
寫一個函數,它的原形是int continumax(char *outputstr,char *intputstr)
功能:
在字符串中找出連續(xù)最長的數字串,并把這個串的長度返回,
并把這個最長數字串付給其中一個函數參數outputstr所指內存。
例如:"abcd12345ed125ss123456789"的首地址傳給intputstr后,函數將返回9,
outputstr所指的值為123456789
26.左旋轉字符串
題目:
定義字符串的左旋轉操作:把字符串前面的若干個字符移動到字符串的尾部。
如把字符串abcdef左旋轉2位得到字符串cdefab。請實現字符串左旋轉的函數。
要求時間對長度為n的字符串操作的復雜度為O(n),輔助內存為O(1)。
27.跳臺階問題(其實這是斐波拉茨公式)
題目:一個臺階總共有n級,如果一次可以跳1級,也可以跳2級。
求總共有多少總跳法,并分析算法的時間復雜度。
/----------------------------
Copyright by yuucyf. 2011.08.16
-----------------------------/
include "stdafx.h"
include <iostream>
using namespace std;
int JumpStep(int n)
{
if (n <= 0) return 0;
if (n == 1 || n == 2) return n;
return (JumpStep(n-1) + JumpStep(n-2));
}
int _tmain(int argc, _TCHAR* argv[])
{
int nStep = 0;
cout << "請輸入臺階數:";
cin >> nStep;
cout << "臺階數為" << nStep << ",那么總共有" << JumpStep(nStep) << "種跳法." << endl;
return 0;
}
這道題最近經常出現,包括MicroStrategy等比較重視算法的公司
都曾先后選用過個這道題作為面試題或者筆試題。
28.整數的二進制表示中1的個數
題目:輸入一個整數,求該整數的二進制表達中有多少個1。
例如輸入10,由于其二進制表示為1010,有兩個1,因此輸出2。
hamming_weight
int calculate_one(int n)
{
n = (n&0x55555555) + ((n>>1)&0x55555555);
n = (n&0x33333333) + ((n>>2)&0x33333333);
n = (n&0x0f0f0f0f) + ((n>>4)&0x0f0f0f0f);
n = (n&0x00ff00ff) + ((n>>8)&0x00ff00ff);
n = (n&0x0000ffff) + ((n>>16)&0x0000ffff);
return n;
}
方法二
int calculate_one(int n)
{
int count=0;
while(n != 0){
n &= n-1;
count ++;
}
return count;
}
29.棧的push、pop序列
題目:輸入兩個整數序列。其中一個序列表示棧的push順序,
判斷另一個序列有沒有可能是對應的pop順序。
為了簡單起見,我們假設push序列的任意兩個整數都是不相等的。
比如輸入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一個pop系列。
因為可以有如下的push和pop序列:
push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,
這樣得到的pop序列就是4、5、3、2、1。
但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。
思路是:讓輸入的push序列與pop序列的第一位相比較,如不同,則進棧,若相同,則跳過,同時pop序列的元素也向后移動一位。
include <iostream>
include <stack>
using namespace std;
bool isPopSerial(int push[], int pop[], int n)//我自己寫的一種方法,注意函數名
{
int i=0,j=0;
stack<int> mystack;
while(i < n)//只要沒有全部將push數組push到棧中
{
mystack.push(push[i]);
i++;
while(!mystack.empty() && mystack.top() == pop[j])
{
mystack.pop();
j++;
}
}
if( mystack.empty() && j==n)//最后是pop序列的唯一條件:棧變空了,且pop序列游標到了最后
return true;
return false;//除此之外都不是pop序列
}
30.在從1到n的正數中1出現的次數
題目:輸入一個整數n,求從1到n這n個整數的十進制表示中1出現的次數。
include<iostream>
2 #include<string>
3 using namespace std;
4
5 int NumbersOf1sFrom1ToN(unsigned int n)
6 {
7 int currentN = n;
8
9 //計數器
10 int cnt = 0;
11
12 //商,計算該數字包含多少個10,100,1000等
13 int quotient = 0;
14
15 //余數,計算除去“整”的包含,剩下的數字包含的1的個數
16 int remainder = 0;
17
18 //每一輪循環(huán)中的權重,分別記錄10,100,1000中包含多少個位1,十位1,百位1;
19 int mult = 1;
20
21 while(currentN)
22 {
23 quotient = currentN / 10;
24 remainder = currentN % 10;
25
26 //包含多少個10,100,1000,乘以對應的數量的個位1,十位1,百位1
27 cnt += quotient * mult;
28
29 //余數大于1,多加一個該輪下的權重
30 if(remainder > 1)
31 {
32 cnt += mult;
33 }
34 //余數等于1
35 else if(remainder == 1)
36 {
37 cnt += n - currentN * mult + 1;
38 }
39
40
41 currentN = currentN / 10;
42 mult *= 10;
43 }
44
45 return cnt;
46 }
47
48 int main()
49 {
50 cout<<"please enter the number N:"<<endl;
51 unsigned int number = 0;
52 cin>>number;
53
54 cout<<"the number of 1s From 1 to N is:"<<endl;
55 cout<<NumbersOf1sFrom1ToN(number)<<endl;
56 return 0;
}
31.一類似于蜂窩的結構的圖,進行搜索最短路徑(要求5分鐘)
迪杰斯特拉算法
include <iostream>
include <iomanip>
include <string>
using namespace std;
define INFINITY 65535//無邊時的權值
define MAX_VERTEX_NUM 10//最大頂點數
typedef struct MGraph{
string vexs[10];//頂點信息
int arcs[10][10];//鄰接矩陣
int vexnum, arcnum;//頂點數和邊數
}MGraph;
int LocateVex(MGraph G, string u)//返回頂點u在圖中的位置
{
for(int i=0; i<G.vexnum; i++)
if(G.vexs[i]==u)
return i;
return -1;
}
void CreateDN(MGraph &G)//構造有向網
{
string v1, v2;
int w;
int i, j, k;
cout<<"請輸入頂點數和邊數:";
cin>>G.vexnum>>G.arcnum;
cout<<"請輸入頂點:";
for(i=0; i<G.vexnum; i++)
cin>>G.vexs[i];
for(i=0; i<G.vexnum; i++)
for(j=0; j<G.vexnum; j++)
G.arcs[i][j]=INFINITY;
cout<<"請輸入邊和權值:"<<endl;
for(k=0; k<G.arcnum; k++)
{
cin>>v1>>v2>>w;
i=LocateVex(G, v1);
j=LocateVex(G, v2);
G.arcs[i][j]=w;
}
}
//迪杰斯特拉算法求有向網G的v0頂點到其余頂點v的最短路徑p[v]及帶權長度D[v]
//p[][]=-1表示沒有路徑,p[v][i]存的是從v0到v當前求得的最短路徑經過的第i+1個頂點(這是打印最短路徑的關鍵),則v0到v的最短路徑即為p[v][0]到p[v][j]直到p[v][j]=-1,路徑打印完畢。
//final[v]為true當且僅當v∈S,即已經求得從v0到v的最短路徑。
void ShortestPath_DIJ(MGraph G, int v0, int p[][MAX_VERTEX_NUM], int D[])
{
int v, w, i, j, min;
bool final[10];
for(v=0; v<G.vexnum; v++)
{
final[v]=false;//設初值
D[v]=G.arcs[v0][v];//D[]存放v0到v得最短距離,初值為v0到v的直接距離
for(w=0; w<G.vexnum; w++)
p[v][w]=-1;//設p[][]初值為-1,即沒有路徑
if(D[v]<INFINITY)//v0到v有直接路徑
{
p[v][0]=v0;//v0到v最短路徑經過的第一個頂點
p[v][1]=v;//v0到v最短路徑經過的第二個頂點
}
}
D[v0]=0;//v0到v0距離為0
final[v0]=true;//v0頂點并入S集
for(i=1; i<G.vexnum; i++)//其余G.vexnum-1個頂點
{//開始主循環(huán),每次求得v0到某個頂點v的最短路徑,并將v并入S集,然后更新p和D
min=INFINITY;
for(w=0; w<G.vexnum; w++)//對所有頂點檢查
if(!final[w] && D[w]<min)//在S集之外(即final[]=false)的頂點中找離v0最近的頂點,將其賦給v,距離賦給min
{
v=w;
min=D[w];
}
final[v]=true;//v并入S集
for(w=0; w<G.vexnum; w++)//根據新并入的頂點,更新不在S集的頂點到v0的距離和路徑數組
{
if(!final[w] && min<INFINITY && G.arcs[v][w]<INFINITY && (min+G.arcs[v][w]<D[w]))
{//w不屬于S集且v0->v->w的距離<目前v0->w的距離
D[w]=min+G.arcs[v][w];//更新D[w]
for(j=0; j<G.vexnum; j++)//修改p[w],v0到w經過的頂點包括v0到v經過的所有頂點再加上頂點w
{
p[w][j]=p[v][j];
if(p[w][j]==-1)//在p[w][]第一個等于-1的地方加上頂點w
{
p[w][j]=w;
break;
}
}
}
}
}
}
void main()
{
int i, j;
MGraph g;
CreateDN(g);
int p[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//最短路徑數組p
int D[MAX_VERTEX_NUM];//最短距離數組D
ShortestPath_DIJ(g, 0, p, D);
cout<<"最短路徑數組p[i][j]如下:"<<endl;
for(i=0; i<g.vexnum; i++)
{
for(j=0; j<g.vexnum; j++)
cout<<setw(3)<<p[i][j]<<" ";
cout<<endl;
}
cout<<g.vexs[0]<<"到各頂點的最短路徑及長度為:"<<endl;
for(i=0; i<g.vexnum; i++)
{
if(i!=0 && D[i]!=INFINITY)
{
cout<<g.vexs[0]<<"-"<<g.vexs[i]<<"的最短路徑長度為:"<<D[i];
cout<<" 最短路徑為:";
for(j=0; j<g.vexnum; j++)
{
if(p[i][j]>-1)
cout<<g.vexs[p[i][j]]<<" ";
}
cout<<endl;
}
else if(D[i]==INFINITY)
cout<<g.vexs[0]<<"-"<<g.vexs[i]<<":"<<"不可達"<<endl;
}
}
有兩個序列a,b,大小都為n,序列元素的值任意整數,無序;
要求:通過交換a,b中的元素,使[序列a元素的和]與[序列b元素的和]之間的差最小。
例如:
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];
include "stdio.h"
include "stdlib.h"
void balanceArray(int a[],int b[],int n);
int sumArray(int a[],int n);
int main(void)
{
int i;
int a[5]={0,1,2,3,4},b[5]={5,6,7,8,9};
balanceArray(a,b,5);
for(i=0;i<5;i++)
printf("%3d",a[i]);
printf("\n");
for(i=0;i<5;i++)
printf("%3d",b[i]);
printf("\n");
return 0;
}
void balanceArray(int a[],int b[],int n)
{
int p,q;
int i,j,itemDValue,sumDValue,tmp,flag=1;
if(sumArray(a,n) < sumArray(b,n))
{
p = b;
q = a;
}
while(flag)
{
flag=!flag;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
itemDValue = p[i]-q[j];
sumDValue = sumArray(p,n) - sumArray(q,n);
if((itemDValue < sumDValue)&&(itemDValue > 0))
{
flag=!flag;
tmp = p[i];
p[i] = q[j];
q[j] = tmp;
}
}
}
}
}
int sumArray(int a[],int n)
{
int i,count=0;
for(i=0;i<n;i++)
count += a[i];
return count;
}
實現一個挺高級的字符匹配算法:
給一串很長字符串,要求找到符合要求的字符串,例如目的串:123
1******3***2 ,12*****3這些都要找出來
其實就是類似一些和諧系統。。。。。
實現一個隊列。
隊列的應用場景為:
一個生產者線程將int類型的數入列,一個消費者線程將int類型的數出列
求一個矩陣中最大的二維矩陣(元素和最大).如:
1 2 0 3 4
2 3 4 5 1
1 1 5 3 0
中最大的是:
4 5
5 3
要求:(1)寫出算法;(2)分析時間復雜度;(3)用C寫出關鍵代碼
//非最優(yōu)解
include<iostream>
using namespace std;
int max_matrix(int (*array)[5], int maxx, int maxy, int& posi, int& posj)
{
int max = 0;
int i = 0, j = 0;
while(i < maxx - 1)
{
j = 0;
while( j < maxy - 1)
{
int t = array[i][j] + array[i+1][j] + array[i][j+1] + array[i+1][j+1];
if( max < t)
{
max = t;
posi = i;
posj = j;
}
j ++;
}
i ++;
}
return max;
}
int main()
{
int a[3][5] = {{1,2,0,3,4}, {2,3,4,5,1}, {1,1,5,3,0}};
int i = 0, j = 0;
int max = max_matrix(a, 3, 5, i, j);
cout << "max num: " << max <<endl;
cout << "matrix: " << endl;
cout << a[i][j] << " " << a[i][j+1] << endl;
cout << a[i+1][j] << " " << a[i+1][j+1] << endl;
}
第36題-40題(有些題目搜集于CSDN上的網友,已標明):
36.引用自網友:longzuo
谷歌筆試:
n支隊伍比賽,分別編號為0,1,2。。。。n-1,已知它們之間的實力對比關系,
存儲在一個二維數組w[n][n]中,w[i][j] 的值代表編號為i,j的隊伍中更強的一支。
所以w[i][j]=i 或者j,現在給出它們的出場順序,并存儲在數組order[n]中,
比如order[n] = {4,3,5,8,1......},那么第一輪比賽就是 4對3, 5對8。.......
勝者晉級,敗者淘汰,同一輪淘汰的所有隊伍排名不再細分,即可以隨便排,
下一輪由上一輪的勝者按照順序,再依次兩兩比,比如可能是4對5,直至出現第一名
編程實現,給出二維數組w,一維數組order 和 用于輸出比賽名次的數組result[n],
求出result。
有n個長為m+1的字符串,
如果某個字符串的最后m個字符與某個字符串的前m個字符匹配,則兩個字符串可以聯接,
問這n個字符串最多可以連成一個多長的字符串,如果出現循環(huán),則返回錯誤。
百度面試:
1.用天平(只能比較,不能稱重)從一堆小球中找出其中唯一一個較輕的,使用x次天平,
最多可以從y個小球中找出較輕的那個,求y與x的關系式。
answer:二分法
2.有一個很大很大的輸入流,大到沒有存儲器可以將其存儲下來,
而且只輸入一次,如何從這個輸入流中隨機取得m個記錄。
3.大量的URL字符串,如何從中去除重復的,優(yōu)化時間空間復雜度
網易有道筆試:
(1).
求一個二叉樹中任意兩個節(jié)點間的最大距離,
兩個節(jié)點的距離的定義是 這兩個節(jié)點間邊的個數,
比如某個孩子節(jié)點和父節(jié)點間的距離是1,和相鄰兄弟節(jié)點間的距離是2,優(yōu)化時間空間復雜度。
(2).
求一個有向連通圖的割點,割點的定義是,如果除去此節(jié)點和與其相關的邊,
有向圖不再連通,描述算法。
40.百度研發(fā)筆試題
引用自:zp155334877
1)設計一個棧結構,滿足一下條件:min,push,pop操作的時間復雜度為O(1)。
2)一串首尾相連的珠子(m個),有N種顏色(N<=10),
設計一個算法,取出其中一段,要求包含所有N中顏色,并使長度最短。
并分析時間復雜度與空間復雜度。
3)設計一個系統處理詞語搭配問題,比如說 中國 和人民可以搭配,
則中國人民 人民中國都有效。要求:
*系統每秒的查詢數量可能上千次;
*詞語的數量級為10W;
*每個詞至多可以與1W個詞搭配
當用戶輸入中國人民的時候,要求返回與這個搭配詞組相關的信息。
41.求固晶機的晶元查找程序
晶元盤由數目不詳的大小一樣的晶元組成,晶元并不一定全布滿晶元盤,
照相機每次這能匹配一個晶元,如匹配過,則拾取該晶元,
若匹配不過,照相機則按測好的晶元間距移到下一個位置。
求遍歷晶元盤的算法 求思路。
42.請修改append函數,利用這個函數實現:
兩個非降序鏈表的并集,1->2->3 和 2->3->5 并為 1->2->3->5
另外只能輸出結果,不能修改兩個鏈表的數據。
43.遞歸和非遞歸倆種方法實現二叉樹的前序遍歷。
44.騰訊面試題:
1.設計一個魔方(六面)的程序。
2.有一千萬條短信,有重復,以文本文件的形式保存,一行一條,有重復。
請用5分鐘時間,找出重復出現最多的前10條。
3.收藏了1萬條url,現在給你一條url,如何找出相似的url。(面試官不解釋何為相似)
45.雅虎:
1.對于一個整數矩陣,存在一種運算,對矩陣中任意元素加一時,需要其相鄰(上下左右)
某一個元素也加一,現給出一正數矩陣,判斷其是否能夠由一個全零矩陣經過上述運算得到。
2.一個整數數組,長度為n,將其分為m份,使各份的和相等,求m的最大值
比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
{3,6}{2,4,3} m=2
{3,3}{2,4}{6} m=3 所以m的最大值為3
46.搜狐:
四對括號可以有多少種匹配排列方式?比如兩對括號可以有兩種:()()和(())
47.創(chuàng)新工場:
求一個數組的最長遞減子序列 比如{9,4,3,2,5,4,3,2}的最長遞減子序列為{9,5,4,3,2}
48.微軟:
一個數組是由一個遞減數列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移兩位形成的,在這種數組中查找某一個數。
49.一道看上去很嚇人的算法面試題:
如何對n個數進行排序,要求時間復雜度O(n),空間復雜度O(1)
50.網易有道筆試:
1.求一個二叉樹中任意兩個節(jié)點間的最大距離,兩個節(jié)點的距離的定義是 這兩個節(jié)點間邊的個數,
比如某個孩子節(jié)點和父節(jié)點間的距離是1,和相鄰兄弟節(jié)點間的距離是2,優(yōu)化時間空間復雜度。
2.求一個有向連通圖的割點,割點的定義是,
如果除去此節(jié)點和與其相關的邊,有向圖不再連通,描述算法。
51.和為n連續(xù)正數序列。
題目:輸入一個正數n,輸出所有和為n連續(xù)正數序列。
例如輸入15,由于1+2+3+4+5=4+5+6=7+8=15,所以輸出3個連續(xù)序列1-5、4-6和7-8。
分析:這是網易的一道面試題。
52.二元樹的深度。
題目:輸入一棵二元樹的根結點,求該樹的深度。
從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。
例如:輸入二元樹:
10
/ \
6 14
/ / \
4 12 16
輸出該樹的深度3。
二元樹的結點定義如下:
struct SBinaryTreeNode // a node of the binary tree
{
int m_nValue; // value of node
SBinaryTreeNode *m_pLeft; // left child of node
SBinaryTreeNode *m_pRight; // right child of node
};
分析:這道題本質上還是考查二元樹的遍歷。
53.字符串的排列。
題目:輸入一個字符串,打印出該字符串中字符的所有排列。
例如輸入字符串abc,則輸出由字符a、b、c所能排列出來的所有字符串
abc、acb、bac、bca、cab和cba。
分析:這是一道很好的考查對遞歸理解的編程題,
因此在過去一年中頻繁出現在各大公司的面試、筆試題中。
54.調整數組順序使奇數位于偶數前面。
題目:輸入一個整數數組,調整數組中數字的順序,使得所有奇數位于數組的前半部分,
所有偶數位于數組的后半部分。要求時間復雜度為O(n)。
題目:類CMyString的聲明如下:
class CMyString
{
public:
CMyString(char* pData = NULL);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator = (const CMyString& str);
private:
char* m_pData;
};
請實現其賦值運算符的重載函數,要求異常安全,即當對一個對象進行賦值時發(fā)生異常,對象的狀態(tài)不能改變。
56.最長公共字串。
題目:如果字符串一的所有字符按其在字符串中的順序出現在另外一個字符串二中,
則字符串一稱之為字符串二的子串。
注意,并不要求子串(字符串一)的字符必須連續(xù)出現在字符串二中。
請編寫一個函數,輸入兩個字符串,求它們的最長公共子串,并打印出最長公共子串。
例如:輸入兩個字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它們的最長公共子串,
則輸出它們的長度4,并打印任意一個子串。
分析:求最長公共子串(Longest Common Subsequence, LCS)是一道非常經典的動態(tài)規(guī)劃題,
因此一些重視算法的公司像MicroStrategy都把它當作面試題。
57.用倆個棧實現隊列。
題目:某隊列的聲明如下:
template<typename T> class CQueue
{
public:
CQueue() {}
~CQueue() {}
void appendTail(const T& node); // append a element to tail
void deleteHead(); // remove a element from head
private:
T> m_stack1;
T> m_stack2;
};
分析:從上面的類的聲明中,我們發(fā)現在隊列中有兩個棧。
因此這道題實質上是要求我們用兩個棧來實現一個隊列。
相信大家對棧和隊列的基本性質都非常了解了:棧是一種后入先出的數據容器,
因此對隊列進行的插入和刪除操作都是在棧頂上進行;隊列是一種先入先出的數據容器,
我們總是把新元素插入到隊列的尾部,而從隊列的頭部刪除元素。
58.從尾到頭輸出鏈表。
題目:輸入一個鏈表的頭結點,從尾到頭反過來輸出每個結點的值。鏈表結點定義如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
分析:這是一道很有意思的面試題。
該題以及它的變體經常出現在各大公司的面試、筆試題中。
59.不能被繼承的類。
題目:用C++設計一個不能被繼承的類。
分析:這是Adobe公司2007年校園招聘的最新筆試題。
這道題除了考察應聘者的C++基本功底外,還能考察反應能力,是一道很好的題目。
60.在O(1)時間內刪除鏈表結點。
題目:給定鏈表的頭指針和一個結點指針,在O(1)時間刪除該結點。鏈表結點的定義如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
函數的聲明如下:
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);
分析:這是一道廣為流傳的Google面試題,能有效考察我們的編程基本功,還能考察我們的反應速度,
更重要的是,還能考察我們對時間復雜度的理解。
61.找出數組中兩個只出現一次的數字
題目:一個整型數組里除了兩個數字之外,其他的數字都出現了兩次。
請寫程序找出這兩個只出現一次的數字。要求時間復雜度是O(n),空間復雜度是O(1)。
分析:這是一道很新穎的關于位運算的面試題。
62.找出鏈表的第一個公共結點。
題目:兩個單向鏈表,找出它們的第一個公共結點。
鏈表的結點定義為:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
分析:這是一道微軟的面試題。微軟非常喜歡與鏈表相關的題目,
因此在微軟的面試題中,鏈表出現的概率相當高。
63.在字符串中刪除特定的字符。
題目:輸入兩個字符串,從第一字符串中刪除第二個字符串中所有的字符。例如,輸入”They are students.”和”aeiou”,
則刪除之后的第一個字符串變成”Thy r stdnts.”。
分析:這是一道微軟面試題。在微軟的常見面試題中,與字符串相關的題目占了很大的一部分,
因為寫程序操作字符串能很好的反映我們的編程基本功。
- 尋找丑數。
題目:我們把只包含因子2、3和5的數稱作丑數(Ugly Number)。例如6、8都是丑數,
但14不是,因為它包含因子7。習慣上我們把1當做是第一個丑數。
求按從小到大的順序的第1500個丑數。
分析:這是一道在網絡上廣為流傳的面試題,據說google曾經采用過這道題。
65.輸出1到最大的N位數
題目:輸入數字n,按順序輸出從1最大的n位10進制數。比如輸入3,
則輸出1、2、3一直到最大的3位數即999。
分析:這是一道很有意思的題目。看起來很簡單,其實里面卻有不少的玄機。
66.顛倒棧。
題目:用遞歸顛倒一個棧。例如輸入棧{1, 2, 3, 4, 5},1在棧頂。
顛倒之后的棧為{5, 4, 3, 2, 1},5處在棧頂。
67.倆個閑玩娛樂。
1.撲克牌的順子
從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續(xù)的。
2-10為數字本身,A為1,J為11,Q為12,K為13,而大小王可以看成任意數字。
2.n個骰子的點數。
把n個骰子扔在地上,所有骰子朝上一面的點數之和為S。輸入n,
打印出S的所有可能的值出現的概率。
68.把數組排成最小的數。
題目:輸入一個正整數數組,將它們連接起來排成一個數,輸出能排出的所有數字中最小的一個。
例如輸入數組{32, 321},則輸出這兩個能排成的最小數字32132。
請給出解決問題的算法,并證明該算法。
分析:這是09年6月份百度的一道面試題,
從這道題我們可以看出百度對應聘者在算法方面有很高的要求。
69.旋轉數組中的最小元素。
題目:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個排好序的數組的一個旋轉,
輸出旋轉數組的最小元素。例如數組{3, 4, 5, 1, 2}為{1, 2, 3, 4, 5}的一個旋轉,該數組的最小值為1。
分析:這道題最直觀的解法并不難。從頭到尾遍歷數組一次,就能找出最小的元素,
時間復雜度顯然是O(N)。但這個思路沒有利用輸入數組的特性,我們應該能找到更好的解法。
70.給出一個函數來輸出一個字符串的所有排列。
ANSWER 簡單的回溯就可以實現了。當然排列的產生也有很多種算法,去看看組合數學,
還有逆序生成排列和一些不需要遞歸生成排列的方法。
印象中Knuth的<TAOCP>第一卷里面深入講了排列的生成。這些算法的理解需要一定的數學功底,
也需要一定的靈感,有興趣最好看看。
71.數值的整數次方。
題目:實現函數double Power(double base, int exponent),求base的exponent次方。
不需要考慮溢出。
分析:這是一道看起來很簡單的問題。可能有不少的人在看到題目后30秒寫出如下的代碼:
double Power(double base, int exponent)
{
double result = 1.0;
for(int i = 1; i <= exponent; ++i)
result *= base;
return result;
}
題目:設計一個類,我們只能生成該類的一個實例。
分析:只能生成一個實例的類是實現了Singleton模式的類型。
73.對策字符串的最大長度。
題目:輸入一個字符串,輸出該字符串中對稱的子字符串的最大長度。
比如輸入字符串“google”,由于該字符串里最長的對稱子字符串是“goog”,因此輸出4。
分析:可能很多人都寫過判斷一個字符串是不是對稱的函數,這個題目可以看成是該函數的加強版。
74.數組中超過出現次數超過一半的數字
題目:數組中有一個數字出現的次數超過了數組長度的一半,找出這個數字。
分析:這是一道廣為流傳的面試題,包括百度、微軟和Google在內的多家公司都
曾經采用過這個題目。要幾十分鐘的時間里很好地解答這道題,
除了較好的編程能力之外,還需要較快的反應和較強的邏輯思維能力。
75.二叉樹兩個結點的最低共同父結點
題目:二叉樹的結點定義如下:
struct TreeNode
{
int m_nvalue;
TreeNode* m_pLeft;
TreeNode* m_pRight;
};
輸入二叉樹中的兩個結點,輸出這兩個結點在數中最低的共同父結點。
分析:求數中兩個結點的最低共同結點是面試中經常出現的一個問題。這個問題至少有兩個變種。
76.復雜鏈表的復制
題目:有一個復雜鏈表,其結點除了有一個m_pNext指針指向下一個結點外,
還有一個m_pSibling指向鏈表中的任一結點或者NULL。其結點的C++定義如下:
struct ComplexNode
{
int m_nValue;
ComplexNode* m_pNext;
ComplexNode* m_pSibling;
};
下圖是一個含有5個結點的該類型復雜鏈表。
圖中實線箭頭表示m_pNext指針,虛線箭頭表示m_pSibling指針。為簡單起見,
指向NULL的指針沒有畫出。
請完成函數ComplexNode* Clone(ComplexNode* pHead),以復制一個復雜鏈表。
分析:在常見的數據結構上稍加變化,這是一種很新穎的面試題。
要在不到一個小時的時間里解決這種類型的題目,我們需要較快的反應能力,
對數據結構透徹的理解以及扎實的編程功底。
77.關于鏈表問題的面試題目如下:
1.給定單鏈表,檢測是否有環(huán)。
使用兩個指針p1,p2從鏈表頭開始遍歷,p1每次前進一步,p2每次前進兩步。如果p2到達鏈表尾部,
說明無環(huán),否則p1、p2必然會在某個時刻相遇(p1==p2),從而檢測到鏈表中有環(huán)。
2.給定兩個單鏈表(head1, head2),檢測兩個鏈表是否有交點,如果有返回第一個交點。
如果head1==head2,那么顯然相交,直接返回head1。
否則,分別從head1,head2開始遍歷兩個鏈表獲得其長度len1與len2,假設len1>=len2,
那么指針p1由head1開始向后移動len1-len2步,指針p2=head2,
下面p1、p2每次向后前進一步并比較p1p2是否相等,如果相等即返回該結點,
否則說明兩個鏈表沒有交點。
3.給定單鏈表(head),如果有環(huán)的話請返回從頭結點進入環(huán)的第一個節(jié)點。
運用題一,我們可以檢查鏈表中是否有環(huán)。
如果有環(huán),那么p1p2重合點p必然在環(huán)中。從p點斷開環(huán),
方法為:p1=p, p2=p->next, p->next=NULL。此時,原單鏈表可以看作兩條單鏈表,
一條從head開始,另一條從p2開始,于是運用題二的方法,我們找到它們的第一個交點即為所求。
4.只給定單鏈表中某個結點p(并非最后一個結點,即p->next!=NULL)指針,刪除該結點。
辦法很簡單,首先是放p中數據,然后將p->next的數據copy入p中,接下來刪除p->next即可。
5.只給定單鏈表中某個結點p(非空結點),在p前面插入一個結點。
辦法與前者類似,首先分配一個結點q,將q插入在p后,接下來將p中的數據copy入q中,
然后再將要插入的數據記錄在p中。
78.鏈表和數組的區(qū)別在哪里?
分析:主要在基本概念上的理解。
但是最好能考慮的全面一點,現在公司招人的競爭可能就在細節(jié)上產生,
誰比較仔細,誰獲勝的機會就大。
1.編寫實現鏈表排序的一種算法。說明為什么你會選擇用這樣的方法?
2.編寫實現數組排序的一種算法。說明為什么你會選擇用這樣的方法?
3.請編寫能直接實現strstr()函數功能的代碼。
80.阿里巴巴一道筆試題
問題描述:
12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種?
這個筆試題,很YD,因為把某個遞歸關系隱藏得很深。