List reverse(List l) {
if(!l) return l;
list cur = l.next;
list pre = l;
list tmp;
pre.next = null;
while ( cur ) {
tmp = cur;
cur = cur.next;
tmp.next = pre
pre = tmp;
}
return tmp;
}
2、反轉一個鏈表。遞歸算法。
List resverse(list l) {
if(!l || !l.next) return l;
List n = reverse(l.next);
l.next.next = l;
l.next=null;
}
return n;
}
3、廣度優先遍歷二叉樹。
void BST(Tree t) {
Queue q = new Queue();
q.enque(t);
Tree t = q.deque();
while(t) {
System.out.println(t.value);
q.enque(t.left);
q.enque(t.right);
t = q.deque();
}
}
class Node {
Tree t;
Node next;
}
class Queue {
Node head;
Node tail;
public void enque(Tree t){
Node n = new Node();
n.t = t;
if(!tail){
tail = head = n;
} else {
tail.next = n;
tail = n;
}
}
public Tree deque() {
if (!head) {
return null;
} else {
Node n = head;
head = head.next;
return n.t;
}
}
4、輸出一個字符串所有排列。注意有重複字符。
char[] p;
void perm(char s[], int i, int n){
int j;
char temp;
for(j=0;j<n;++j){
if(j!=0 && s[j]==s[j-1]);
elseif(s[j]!='@'){
p[i]=s[j];
s[j]='@';
if(i==n-1){
p[n]='/0';
printf("%s", p);
}else{
perm(s,i+1,n);
}
s[j]=p[i];
}
}
}
void main() {
char s[N];
sort(s);
perm(s,0,strlen(s));
}
5、輸入一個字符串,輸出長型整數。
long atol(char *str){
char *p = str;
long l=1;m=0;
if (*p=='-') {
l=-1;
++p;
}
while(isDigit(*p)){
m = m*10 + p;
++p;
}
if(!p) return m*l;
else return error;
}
6、判斷一個鏈表是否有循環。
int isLoop(List l) {
if ( ! l) return - 1 ;
List s = l.next;
while (s && s != l) {
s = s.next;
}
if ( ! s) return - 1 ;
else reutrn 1 ;
}
int isLoop(List l){
if(!l) return 0;
p=l.next;
wihle(p!=l&&p!=null) {
l.next=l;
l=p;p=p.next;
}
if(p=l) return 1;
return 0;
}
實際上,在我的面試過程中,還問到了不破壞結構的其他算法。
我的答案是從鏈表頭開始遍歷,如果節點next指針指向自身,則循環存在;否則將next指針指向自身,遍歷下一個節點。直至next指針爲空,此時鏈表無循環。
http://en.wikipedia.org/wiki/Floyd's_cycle-finding_algorithm
http://ostermiller.org/find_loop_singly_linked_list.html
http://www.cnblogs.com/wqguan/archive/2006/06/20/
不是隨便兩個步長不同的指針都會在循環鏈表上相遇。一個充分條件是,兩個遍歷指針步長相差1。最好是1,2這兩個步長,這樣就可以進而求出循環的位置和鏈表的大小。
7、反轉一個字符串。
void reverse( char * str) {
char tmp;
int len;
len = strlen(str);
for ( int i = 0 ;i < len / 2 ; ++ i) {
tmp = char [i];
str[i] = str[len - i - 1 ];
str[len - i - 1 ] = tmp;
}
}
8、實現strstr函數。
int strstr(char[] str, char[] par){
int i=0;
int j=0;
while(str[i] && str[j]){
if(str[i]==par[j]){
++i;
++j;
}else{
i=i-j+1;
j=0;
}
}
if(!str[j]) return i-strlen(par);
else return -1;
}
9、實現strcmp函數。
int strcmp(char* str1, char* str2){
while(*str1 && *str2 && *str1==*str2){
++str1;
++str2;
}
return *str1-*str2;
}
10、求整形中二進制1的位數
求一個整形中1的位數。
int f( int x) {
int n = 0 ;
while (x) {
++ n;
x &= x - 1 ;
}
return n;
}
11、漢諾塔問題。
void tower(n,x,y,z){
if(n==1) move(x,z);
else {
tower(n-1, x,z,y);
move(x,z);
tower(n-1, y,x,z);
}
}
12、漢諾塔最小步數
三柱漢諾塔最小步數。
int f3(n) {
if (f3[n]) return f3[n];
else {
if (n == 1 ) {
f3[n] = 1 ;
return 1 ;
}
f3[n] = 2 * f3(n - 1 ) + 1 ;
return f3[n];
}
}
四柱漢諾塔最小步數。
int f4(n){
if(f4[n]==0){
if(n==1) {
f4[1]==1;
return 1;
}
min=2*f4(1)+f3(n-1);
for(int i=2;i<n;++i){
u=2*f4(i)+f3(n-i);
if(u<min) min=u;
}
f4[n]=min;
return min;
} else return f4[n];
}
13、在一個鏈表中刪除另一個鏈表中的元素。
void delete(List m, List n) {
if(!m || !n) return;
List pre = new List();
pre.next=m;
List a=m, b=n,head=pre;
while(a && b){
if(a.value < b.value) {
a=a.next;
pre=pre.next;
}else if(a.value > b.value){
b=b.next;
}else{
a=a.next;
pre.next=a;
}
}
m=head.next;
}
14、一個數組,下標從0到n,元素爲從0到n的整數。判斷其中是否有重複元素。
int hasDuplicate(int[] a, int n){
for(int i=0;i<n;++i){
while(a[i]!=i && a[i]!=-1){
if(a[a[i]]==-1) return 1;
a[i]=a[a[i]];
a[a[i]]=-1;
}
if(a[i]==i) {a[i]=-1;}
}
return 0;
}
15、判斷一顆二叉樹是否平衡。
int isB(Tree t){
if(!t) return 0;
int left=isB(t.left);
int right=isB(t.right);
if( left >=0 && right >=0 && left - right <= 1 || left -right >=-1)
return (left<right)? (right +1) : (left + 1);
else return -1;
}
16、返回一顆二叉樹的深度。
int depth(Tree t){
if(!t) return 0;
else {
int a=depth(t.right);
int b=depth(t.left);
return (a>b)?(a+1):(b+1);
}
}
17、兩個鏈表,一升一降。合併爲一個升序鏈表。
List merge(List a, List d) {
List a1 = reverse(d);
List p = q = new List();
while ( a && a1 ) {
if (a.value < a1.value) {
p.next = a;
a = a.next;
} else {
p.next = a1;
a1 = a1.next;
}
p = p.next;
}
if (a) p.next = a;
elseif(a1) p.next = a1;
return q.next;
}
鏈表逆序本來就是O(N),所以這道題再爛的做法也不會超過O(N)。我覺得先逆序再歸並不會比設計一個個巧妙的方法一次組成目標鏈表慢多少的
18、將長型轉換爲字符串。
char* ltoa(long l){
char[N] str;
int i=1,n=1;
while(!(l/i<10)){i*=10;++n}
char* str=(char*)malloc(n*sizeof(char));
int j=0;
while(l){
str[j++]=l/i;
l=l%i;
i/=10;
}
return str;
}
19、用一個數據結構實現
if (x == 0) y = a;
else y = b;
j[] = {a,b};
y=j[x];
20、在雙向鏈表中刪除指定元素。
void del(List head, List node){
List pre=new List();
pre.next = head;
List cur = head;
while(cur && cur!=node){
cur=cur.next;
pre=pre.next;
}
if(!cur) return;
List post = cur.next;
pre.next=cur.next;
post.last=cur.last;
return;
}
21、不重複地輸出升序數組中的元素。
void outputUnique( char [] str, int n) {
if (n <= 0 ) return ;
elseif(n == 1 ) putchar(str[ 0 ]);
else {
int i = 0 ,j = 1 ;
putchar(str[ 0 ]);
while (j < n) {
if (str[j] !== str[i]) {
putchar(str[j]);
i = j;
}
++ j;
}
}
}
22、面試過程中我還遇到了下面幾題:
1、如何刪除鏈表的倒數第m的元素?我的方法是先用pre指針從鏈表頭開始步進m,新建pst節點next指針指向頭節點,cur指針指向頭節點,然後pre,cur,post三個指針一起步進,當pre指向鏈表結尾的時候cur指向倒數第m個元素,最後利用pst指針刪除cur指向元素。
2、如何判斷一個字符串是對稱的?如a,aa,aba。設置頭尾指針同時向中間比較靠齊直至相遇。
3、如何利用2函數找出一個字符串中的所有對稱子串?以子串頭指針和尾指針爲循環變量設置兩個嵌套的循環以找出所有子串,對每個子串應用2函數。