原题如下:用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