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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值