锁定老帖子 主题:公司笔试算法题
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (3)
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-07
最后修改:2011-03-07
解题思路:
1.对数组进行全排列 2.去掉不符合条件的排列 public class Test { public static void main(String[] args) { int[] initData = { 1, 2, 3, 4, 5 }; // 对数组进行全排列 perm(initData, 0, initData.length); } /** * 对数组进行全排列,并打印符合条件的数组(4不能在第3位,3跟5不能相连) * * @param t 要排列的数组 * @param start 起始位置 * @param end 结束位置 */ public static void perm(int[] t, int start, int end) { if (start == end) { // 如果4在第三位或者3跟5相连,则不打印 if (t[2] == 4 || is3NextTo5(t)) { } else { // 打印符合条件的数据 for (int i = 0; i < t.length; i++) { System.out.print(t[i]); } System.out.println(); } } else { for (int i = start; i < end; i++) { int temp = t[start]; t[start] = t[i]; t[i] = temp; //递归 perm(t, start + 1, end); temp = t[start]; t[start] = t[i]; t[i] = temp; } } } /** * 判断3跟5是否相连 * * @param t 数组 * @return true or false */ public static boolean is3NextTo5(int[] t) { for (int i = 0; i < t.length - 1; i++) { if (t[i] == 3 && t[i + 1] == 5) return true; } for (int i = 0; i < t.length - 1; i++) { if (t[i] == 5 && t[i + 1] == 3) return true; } return false; } } |
|
返回顶楼 | |
发表时间:2011-03-07
这样没有意思!全排列才挑出不合适的!
|
|
返回顶楼 | |
发表时间:2011-03-07
piao_bo_yi 写道 没考虑过用无相连通图求全排列,学习了。
我的思路:递归求全排列+条件筛选,代码: public static void permutation(int[] src, int m) { if (m == src.length) { if (src.length > 3 && src[2] != 4) { boolean bPrint = true; for (int i = 0; i < src.length - 1; i++) { if ((src[i] == 3 && src[i + 1] == 5) || (src[i] == 5 && src[i + 1] == 3)) { bPrint = false; } } if (bPrint) print(src); } } else { for (int i = m; i < src.length; i++) { swap(src, m, i); permutation(src, m + 1); swap(src, m, i); } } } public static void print(int[] src) { for (int i = 0; i < src.length; i++) System.out.print(src[i]); System.out.println(); } private static void swap(int[] src, int m, int i) { int t = src[m]; src[m] = src[i]; src[i] = t; } 我也觉得用递归比较好,不过递归里的else没看明白。下面是我的代码,贴出来分享,C#写的。 public static int allListNum = 0; public void ListNum(ArrayList numList, ArrayList printList) { if (numList.Count == 1) { printList.Add(numList[0]); if ((int)printList[0] == 4) return; int i, j; for (i = 0; i < printList.Count; i++) { if ((int)printList[i] == 3) { if (i - 1 >= 0) { if ((int)printList[i - 1] == 5) return; } if (i + 1 <= printList.Count - 1) { if ((int)printList[i + 1] == 5) return; } } } for (j = 0; j < printList.Count; j++) { Console.Write((int)printList[j]); } allListNum++; Console.Write(";"); printList.Clear(); } else { for (int i = 0; i < numList.Count; i++) { bool appeared = false; for (int j = 0; j < i; j++) { if ((int)numList[j] == (int)numList[i]) { appeared = true; break; } } if (appeared) { continue; } ArrayList newList = new ArrayList(); ArrayList printNewList = new ArrayList(); newList = (ArrayList)numList.Clone(); printNewList = (ArrayList)printList.Clone(); printNewList.Add(numList[i]); newList.RemoveAt(i); ListNum(newList, printNewList); } } } 好像比较耗内存。。。。第一次发帖,包涵。 |
|
返回顶楼 | |
发表时间:2011-03-07
强强爱妍妍 写道 楼上的,2凭啥不能在6后面?
假如2在6后面 不就重复了嘛 |
|
返回顶楼 | |
发表时间:2011-03-07
最后修改:2011-03-07
楼上的貌似都没有处理两个2的重复排列问题呀。
这里给一个非递归的实现: public class Qiz { private static final int[] ORIGINAL = {1, 2, 2, 3, 4, 5}; private static final int LAST_P = ORIGINAL.length - 1; private static int s[] = new int[ORIGINAL.length]; //全排列栈 public static void main(String[] args) { boolean isLast2Used = false; //第二个2已被使用 Set<Integer> usedNums = new HashSet<Integer>(); Arrays.fill(s, -1); int p = 0; //当前位置 int count = 0; //结果计数 do { int num = ++s[p]; //当前位置的取值 if (num > LAST_P) { //回溯 p--; if (p >= 0) { //清空当前取值标记,注意在这里不能用num来代替s[p],因为p已经变了 usedNums.remove(s[p]); if (s[p] == 3) { isLast2Used = false; } } } else { if (!(usedNums.contains(num) || is3NextTo5(p) || (p == 2 && ORIGINAL[num] == 4) || (num == 2 && isLast2Used))) { //如果当前取值合法 if (p == LAST_P) { //如果已找到一个解 System.out.print((++count) + ":"); for (int i : s) { System.out.print(ORIGINAL[i] + " "); } System.out.println(); } else { //继续搜索前先设置有关标志 usedNums.add(num); if (num == 3) { isLast2Used = true; } s[++p] = -1; //前进一个位置 } } } } while (p > -1); } private static boolean is3NextTo5(int p) { if (p > 0) { int num1 = ORIGINAL[s[p]]; int num2 = ORIGINAL[s[p-1]]; if ((num1 == 3 && num2 == 5) || (num1 == 5 && num2 == 3)) { return true; } } return false; } } |
|
返回顶楼 | |
发表时间:2011-03-07
2不能在6后面。很出彩的理解啊,不仔细想还想不通。
我那代码里else后面的bool变量就是处理两个2重复的问题啊~~~~ |
|
返回顶楼 | |
发表时间:2011-03-07
kidneyball 写道 楼上的貌似都没有处理两个2的重复排列问题呀。
这里给一个非递归的实现: public class Qiz { private static final int[] ORIGINAL = {1, 2, 2, 3, 4, 5}; private static final int LAST_P = ORIGINAL.length - 1; private static int s[] = new int[ORIGINAL.length]; //全排列栈 public static void main(String[] args) { boolean isLast2Used = false; //第二个2已被使用 Set<Integer> usedNums = new HashSet<Integer>(); Arrays.fill(s, -1); int p = 0; //当前位置 int count = 0; //结果计数 do { int num = ++s[p]; //当前位置的取值 if (s[p] > LAST_P) { //回溯 p--; if (p >= 0) { //清空当前取值标记 usedNums.remove(s[p]); if (s[p] == 3) { isLast2Used = false; } } } else { if (!(usedNums.contains(num) || is3NextTo5(p) || (p == 2 && ORIGINAL[s[p]] == 4) || (s[p] == 2 && isLast2Used))) { //如果当前取值合法 if (p == LAST_P) { //如果已找到一个解 System.out.print((++count) + ":"); for (int i : s) { System.out.print(ORIGINAL[i] + " "); } System.out.println(); } else { //继续搜索前先设置有关标志 usedNums.add(num); if (num == 3) { isLast2Used = true; } s[++p] = -1; //前进一个位置 } } } } while (p > -1); } private static boolean is3NextTo5(int p) { if (p > 0) { int num1 = ORIGINAL[s[p]]; int num2 = ORIGINAL[s[p-1]]; if ((num1 == 3 && num2 == 5) || (num1 == 5 && num2 == 3)) { return true; } } return false; } } 兄弟能不能用伪代码描述一下,我看得有点晕。。。 |
|
返回顶楼 | |
发表时间:2011-03-07
最后修改:2011-03-07
haoleng 写道 兄弟能不能用伪代码描述一下,我看得有点晕。。。
我简化一下。 这是非递归回溯求所有数字组合的一个架子,设有N个格子,每个格子的取值可能是由1到M,取值允许重复: public class Qiz { private static final int LAST_P = N - 1; private static int s[] = new int[LAST_P]; //全排列栈 public static void main(String[] args) { Arrays.fill(s, 0); //初始化栈 int p = 0; //用于记录当前位置的指针 //TODO **初始化其他标志变量** do { int num = ++s[p]; //当前位置的取值基于原来的值加1,作为当前位置取值。 if (s[p] > M) { //如果当前位置的取值已经超过了最大允许取值,则回溯到上一位置 //回溯 p--; if (p >= 0) { //TODO **这时指针指向前一位置,该位置的当前取值已不属于解中,清空与这个取值有关的所有标记** } } else { if (/**TODO 其他特殊的判断合法条件,例如如果要全排列可以加入判断当前值不能与之前已确认的值重复**/) { //如果当前取值合法 if (p == LAST_P) { //指针已到最后,说明找到了一个解 //TODO ** 做爱做的事 ** } else { //当前位置取值合法,但指针未到最后,需要继续向前搜索 //TODO ** 当前位置的取值已经确认属于解中,继续搜索前先根据当前取值设置有关标志 ** s[++p] = 0; //前进一个位置,并初始化该位置 } } } } while (p > -1); //位置指针已经退回到起点(即第一个位置的取值已经超过M),结束 } } 其中用TODO **围起来的地方可以根据需要加入自己的代码。如果是全排列的话,M和N相等,并且要加入判断当前值不能与栈中已确认的值重复。 在前一楼,因为全排列的结果还要映射到用于输出的ORIGINAL集合,取值范围是0到ORIGINAL.length-1,所以用了-1作为每个位置的初始值 |
|
返回顶楼 | |
发表时间:2011-03-07
辛苦了~~~~正在学习。
|
|
返回顶楼 | |
发表时间:2011-03-08
看着像宝蓝德中国的题目
|
|
返回顶楼 | |