一著名软件公司的java笔试算法题

 原题如下:用1、2、2、3、4、5这六个数字,用java写一个main函数,打印出所有不同的排列,如:512234、412345等,要求: "4 "不能在第三位, "3 "与 "5 "不能相连.
我看了回贴都没有很好解决,主要是没有排除重复。
解决思路:强化题目,用1、2、2、3、4、5这六个数字排列“递增”序列。其他要求不变。
算法思路:显然是递归,初始序列122345,先从末两位(45)变化(45,54),然后末三位(345)   ...   直到最后六位.怎样解决重复问题?很简单,由于是递增序列,每生成新序列可与前一生成序列比较,如 <放弃当前序列。当然有更好效率,如预先预测。代码如下:
class   test
{  
    //   当前固定部分
    private   String   CurFixPart;
    private   String   PreGenNum;
   
public   static   void   main(String[]   args)
{
  test   t=new   test();
  t.GenControll( "122345 ");
}

//   调整字符串s位置pos字符到最前
private   String   shift(String   s,   int   pos)
{
String   newStr;
if   (s.length()> pos+1)
    newStr=s.substring(pos,   pos+1)
                +s.substring(0,   pos)
                +s.substring(pos+1);
else
    newStr=s.substring(pos)
                +s.substring(0,   pos);
return   newStr;
}

protected   int   Validate(String   newNum)
{
    String   newGenNum=CurFixPart+newNum;
    if   (Integer.valueOf(newGenNum) <=Integer.valueOf(PreGenNum))
        return   0;
    if   (newGenNum.substring(2,3).equals( "4 ")   ||  
              (newGenNum.indexOf( "35 ")!=-1)   ||   (newGenNum.indexOf( "53 ")!=-1))  
        return   0;
           
    PreGenNum=newGenNum;
System.out.println(newGenNum);
return   0;
}
 
public   void   GenControll(String   Base)
{
    PreGenNum= "0 ";
CurFixPart= " ";
GenNext(Base,   0);
}

void   GenNext(String   varPart,   int   curPos)
{
if   (varPart.length()==2)
{
    Validate(varPart);
    Validate(shift(varPart,   1));
    return;
  }
//   Next   Layer
String   newGen=shift(varPart,   curPos);
String   SavedFixPart=CurFixPart;
CurFixPart=CurFixPart+newGen.substring(0,1);
GenNext(newGen.substring(1),   0);
CurFixPart=SavedFixPart;
//   同层递增
if   (curPos==varPart.length()-1)    
    return;
GenNext(varPart,   curPos+1);
}
}
序列122345测试通过。
有什么意见请大家多多提点。

 

1   把问题归结为图结构的遍历问题。实际上6个数字就是六个结点,把六个结点连接成无向连通图,对于每一个结点求这个图形的遍历路径,所有结点的遍历路径就是最后对这6个数字的排列组合结果集。
2   显然这个结果集还未达到题目的要求。从以下几个方面考虑:
    1.   3,5不能相连:实际要求这个连通图的结点3,5之间不能连通,   可在构造图结构时就满足改条件,然后再遍历图。
    2.   不能有重复:   考虑到有两个2,明显会存在重复结果,可以把结果集放在TreeSet中过滤重复结果
    3.   4不能在第三位:   仍旧在结果集中去除满足此条件的结果。

采用二维数组定义图结构,最后的代码是:

import   java.util.Iterator;
import   java.util.TreeSet;

public   class   TestQuestion   {

private   String[]   b   =   new   String[]{ "1 ",   "2 ",   "2 ",   "3 ",   "4 ",   "5 "};
private   int   n   =   b.length;
private   boolean[]   visited   =   new   boolean[n];
private   int[][]   a   =   new   int[n][n];
private   String   result   =   " ";
private   TreeSet   set   =   new   TreeSet();

public   static   void   main(String[]   args)   {
new   TestQuestion().start();
}

private   void   start()   {

//   Initial   the   map   a[][]
for   (int   i   =   0;   i   <   n;   i++)   {
for   (int   j   =   0;   j   <   n;   j++)   {
if   (i   ==   j)   {
a[i][j]   =   0;
}   else   {
        a[i][j]   =   1;
}
}
}

//   3   and   5   can   not   be   the   neighbor.
a[3][5]   =   0;
a[5][3]   =   0;

//   Begin   to   depth search.
for   (int   i   =   0;   i   <   n;   i++)   {
        this.depthFirstSearch(i);
}

//   Print   result   treeset.
Iterator   it   =   set.iterator();
while   (it.hasNext())   {
String   string   =   (String)   it.next();
//   "4 "   can   not   be   the   third   position.
if   (string.indexOf( "4 ")   !=   2)   {
System.out.println(string);
}
}
}

private   void   depthFirstSearch(int   startIndex)   {
visited[startIndex]   =   true;
result   =   result   +   b[startIndex];
if   (result.length()   ==   n)   {
//   Filt   the   duplicate   value.
set.add(result);
}
for(int   j   =   0;   j   <   n;   j++)   {
if   (a[startIndex][j]   ==   1   &&   visited[j]   ==   false)   {
depthFirstSearch(j);
}   else   {
continue;
}
}

//   restore   the   result   value   and   visited   value   after   listing   a   node.
        result   =   result.substring(0,   result.length()   -1);
        visited[startIndex]   =   false;
}
}
3,5不能相连:实际要求这个连通图的结点3,5之间不能连通,   可在构造图结构时就满足改条件,然后再遍历图。
  代码中请注意这几行:
  //   3   and   5   can   not   be   the   neighbor.
  a[3][5]   =   0;
  a[5][3]   =   0;

只要这样定义图,根本不用在代码中写IF   ELSE语句。
实际上基于图的算法好处在于,只要你能定义好满足题目要求的图结构,遍历的结果就是你要的结果,不用任何对遍历结果做任何处理。包括本题中的:4不能在第三位置,3,5不能相连,唯一
性要求,其实都可以在体现在构造的图形结构里,然后直接遍历图取得自己要的结果。而不用再次处理结果集。

只是说这里实际上对其它要求要体现在图结构里有困难(理论上是可以的),但起码3,5不能相接是很好构造的,就是上面的代码段来解释的。

关于图形数据结构建议先看看数据结构的书,主要是将如何利用二维数组描述图结构,再看看图的深度遍历实现原理。最后再应用到这个问题上来,自然就不难明白了。

 

 

补充:由于时间的关系,上面给的代码没有多做考虑。
其实有两方面可以优化一下:
1。Validate   可以学习Struts,利用抽象Validate集去掉If/Else语句。在此不多说。
2。在同层递增前增加“重复预测“减少不必要的重复排序,提高效率。
改进代码如下,其中“//********”处为修改地方
class   test
{  
    //   当前固定部分
    private   String   CurFixPart;
    private   String   PreGenNum;
   
public   static   void   main(String[]   args)
{
  test   t=new   test();
  t.GenControll( "1111111111 ");
}

//   调整字符串s位置pos字符到最前
private   String   shift(String   s,   int   pos)
{
String   newStr;
if   (s.length()> pos+1)
    newStr=s.substring(pos,   pos+1)
                +s.substring(0,   pos)
                +s.substring(pos+1);
else
    newStr=s.substring(pos)
                +s.substring(0,   pos);
return   newStr;
}

protected   int   Validate(String   newNum)
{
    String   newGenNum=CurFixPart+newNum;
 
    if   (Integer.valueOf(newGenNum) <=Integer.valueOf(PreGenNum))
        return   0;
 
    if   (newGenNum.substring(2,3).equals( "4 ")   ||  
              (newGenNum.indexOf( "35 ")!=-1)   ||   (newGenNum.indexOf( "53 ")!=-1))  
        return   0;
           
    PreGenNum=newGenNum;
System.out.println(newGenNum);
return   0;
}
 
public   void   GenControll(String   Base)
{
    PreGenNum= "0 ";
CurFixPart= " ";
GenNext(Base,   0);
}

void   GenNext(String   varPart,   int   curPos)
{
if   (varPart.length()==2)
{
    Validate(varPart);
    Validate(shift(varPart,   1));
    return;
  }
//   Next   Layer
String   newGen=shift(varPart,   curPos);
String   SavedFixPart=CurFixPart;
CurFixPart=CurFixPart+newGen.substring(0,1);
GenNext(newGen.substring(1),   0);
CurFixPart=SavedFixPart;
//*************
//   同层递增
while   (true)
{
if   (curPos==varPart.length()-1)    
    break;
    //   预测是否重复
    curPos++;
if   (Integer.valueOf(CurFixPart+shift(varPart,   curPos)) <=Integer.valueOf(PreGenNum))
        continue;
       
GenNext(varPart,   curPos);
break;
}
//*************
}
}

 

 

 

本来以为很简单,用递归一下就搞定的问题,结果按照递归的常规思路,在打印的时候碰到了很麻烦的问题,费了我不少脑筋,结果答案还是很简单,弄得我做出来了过后都准备把结果放到博客商保存了。其实我做的是字符串排列显示的问题,其中打印时的条件判断语句是根据楼主的特殊要求添加的,诸位参考:
import   java.util.*;
public   class   test   {
public   static   void   main(String[]   arg)   {
Scanner   r=new   Scanner(System.in);
String   s=r.nextLine();
Pailie(s, " ");
}
static   void   Pailie(String   s,   String   p)   {
if(s.length() <1)   {
String   t=p+s;
if(t.charAt(2)!= '4 '   &&   t.contains( "35 ")==false)
System.out.println(t);
}
else   {
for(int   i=0;   i <s.length();   i++)   {
Pailie(s.substring(1),p+s.substring(0,1));
s=s.substring(1)+s.substring(0,1);
}
}
}
}

 

以下是输入字符串abc的运行结果:
abc(输入行)
abc
acb
bca
bac
cab
cba
以下是楼主题的运行结果:
12345(输入行)
12345
12534
12543
13245
13254
14523
14532
14253
14325
15234
15243
15342
15324
23145
23154
24513
24531
24153
24315
25134
25143
25341
25314
21345
21534
21543
34512
34521
34125
34152
34251
34215
31245
31254
31524
31542
32514
32541
32145
32154
45123
45132
45231
45213
45312
45321
41253
41325
41523
41532
42315
42513
42531
42153
43125
43152
43251
43215
51234
51243
51342
51324
52341
52314
52134
52143
53124
53142
53241
53214
54123
54132
54231
54213
54312
54321

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值