EMC面試題

1.一個未排序整數數組,有正負數,重新排列使負數排在正數前面,並且要求不改變原來的 相對順序 比如: input: 1,7,-5,9,-12,15 ans: -5,-12,1,7,9,15 要求時間複雜度O(N),空間O(1) 。 

 

2.有兩堆東西,一堆4個,一堆7個,兩個人開始拿東西,一次可以拿任意個,但只能從一堆中拿。現規定:如果最後剩下一個,而且輪到誰拿誰就輸了。現在你先拿,請問有致勝方法嗎?

 

3.手機上每個數字對應幾個字母,給你一串數字,請你輸出所有可能的字符串。要求是最好的算法。好像這個《編程之美》上面有的。有個疑問,這裏是不是要注意的一點:如果有相同數字出現,由輸出的字母個數可能小於字符串的長度。例如223,可能是BD也可能是AAD。

http://topic.csdn.net/t/20061227/16/5259955.html上有討論。

 

方法1:(遞歸DFS)

         本題除去說如何判斷什麼樣的單詞是一個有意義的單詞這個細節不談(後文中說要先構造一個字典)。那麼問題就轉化爲如何生成所有可能的字符單詞。比如輸入123,要生成所有的可能的“單詞”:#AD,#AE,#AF,#BD,#BE,#BF,#CD,#CE,#CF。

         這是一種全排列的輸出方式,如果從解答樹上就更易看出來了:

                                                                                    23

                                                                              /       |       \

                                                                          (A         B         C)

                                                                       /   |   \    /  |  \     /  |  \

                                                                    (D  E  F) (DEF) (D  E  F)

       所以最適宜用DFS:

代碼:

#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include<time.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<Windows.h>
using namespace std;
//定義電話號碼長度
#define MAX 20
//定義數字對應的字符
char c[10][10]=
{
 "@",//0  沒有的就用@代替,方便看清楚
 "#",//1
 "ABC",//2
 "DEF",//3
 "GHI",//4
 "JKL",//5
 "MNO",//6
 "PQRS",//7
 "TUV",//8
 "WXYZ"//9
};
//定義按鍵的可能字符長度
int total[10]=
{
 1,1,3,3,3,3,3,4,3,4
};

//電話號碼
char number[MAX];
int number_len;
int answer[MAX];//存放位置
void print()
{
 for(int i=0;i<number_len;i++)
 {
  cout<<c[number[i]-'0'][answer[i]];
 }
 cout<<endl;
}
//level表示循環的層次,號碼的位數
//第level個數字
void dfs(int level)
{
 //終止情況
 if(level==number_len)
 {
  print();
  return ;
 }
    
 //該數字是:
 int num=number[level]-'0';
 for(int i=0;i<total[num];i++)
 {
  //對應answer位置賦值
  answer[level]=i;
  dfs(level+1);
 }
}

int _tmain(int argc, _TCHAR* argv[])
{
 while(cin>>number)
 {
  number_len=strlen(number);
  //第0個數字
  dfs(0);
  
 }
 ::system("pause");
 return 0;
}

 

方法2:(非遞歸 神奇的雙重while循環)

注:顯然可以利用這種方法,打印出任意一個N維數組的任意組合。
我的理解:

          這段代碼雖然很精妙,但是要構造出來有點困難,並且理解起來也不好理解,有這個時間的話,還不如直接dfs,因爲實際在程序的運行都是一樣的,沒有必要用巧妙來代替代碼的速度,除非這個方案很常用,或者高效。讓我想起了外星人寫的求PI程序。

 核心:

          參見書本P217。

代碼:

 

#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include<time.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<Windows.h>
using namespace std;
//定義電話號碼長度
#define MAX 20
//定義數字對應的字符
char c[10][10]=
{
 "@",//0  沒有的就用@代替,方便看清楚
 "#",//1
 "ABC",//2
 "DEF",//3
 "GHI",//4
 "JKL",//5
 "MNO",//6
 "PQRS",//7
 "TUV",//8
 "WXYZ"//9
};
//定義按鍵的可能字符長度
int total[10]=
{
 1,1,3,3,3,3,3,4,3,4
};

//電話號碼
char number[MAX];
int number_len;
int answer[MAX];//存放位置


int _tmain(int argc, _TCHAR* argv[])
{
 while(cin>>number)
 {
  number_len=strlen(number);

  while (true)   
  {   
   int k = number_len - 1;   
   //一次循環一次從第k個鍵向前移動一位   
   while (k >= 0)   
   {   
    for (int i = 0; i < number_len; i++)   
     cout << c[number[i]-'0'][answer[i]] << " ";   
    cout << endl;   
    if (answer[k] < total[number[k]-'0'] - 1)   
    {   
     //第k個鍵移動   
     answer[k]++;  

     break; //這裏只要有一個鍵的一個位置發生一次變化,就退出,打印一次。   
    }   
    else  
    {   
     //第k個鍵移動完畢,回到0,開始遍歷上一個鍵。   
     //此時,繼續內部循環。下次循環,處理上一個鍵。   
     answer[k] = 0;   
     k--;   
    }
   }   
   if (k < 0)   
    break;   
  }   
 }
  ::system("pause");
  return 0;
}

 

上面的部分轉自:http://hi.baidu.com/silverxinger/blog/item/9321dd7aa9d2c4290cd7dafe.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章