我有一个数字(int y = 12345)。我想找到如何改变y以找到在洗牌时可以进行的所有可能组合中间的数字。在这种情况下,答案是32541.
我最初尝试将1,2,3,4,5放入列表中,并使用Collections.shuffle获取所有选项并将它们放入sortedSet中。然后获取size()/ 2的索引。但这对于大于123456789的数字不适用......
我还尝试使用递归来使用堆算法切换所有数字。效果稍好一些,但仍无法处理大量数据。见下文。 (我将整数转换为字符串abcdefghij)
public static SortedSet<String> allStrings = new TreeSet<>();
public static SortedSet<String> findMidPerm(String strng) {
permutation("", strng);
return allStrings;
}
private static void permutation(String prefix, String str) {
int n = str.length();
if (n == 0) {
allStrings.add(prefix);
} else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n));
}
}
public static void main(String[] args) {
System.out.println(findMidPerm("abcdefghij"));
}
我目前的想法是不创建所有可能的数字,但找到所有可能组合的确切中心(int x = 33333)。然后查看哪个数字组合最接近该数字。在这种情况下,这是32541或34125.两个数字距离x都是792步。
这是我到目前为止所做的:
public static float findMidPerm(String strng) {
float maxNum = findMaxNum(strng);
float minNum = findMinNum(strng);
float middleNum = findMiddleNum(minNum, maxNum);
return middleNum;
}
private static float findMiddleNum(float minNum, float maxNum) {
return (minNum+maxNum)/2;
}
private static float findMinNum(String strng) {
String s = "";
for (int i = 0; i <= strng.length(); i ++) {
s += i;
}
return Float.parseFloat(s);
}
private static Float findMaxNum(String strng) {
String s = "";
for (int i = strng.length(); i> 0; i --) {
s += i;
}
return Float.parseFloat(s);
}
public static void main(String[] args) {
System.out.println(findMidPerm("abcdefghijklmnop"));
}
现在为创建算法的困难部分找到最接近x的整数的顺序。有没有人有任何想法如何实现这一目标?
答案 0 :(得分:1)
(这是原始问题的答案,如何找到所有排列的中位数,而不是XY问题,如何找到最接近给定数字的排列。)
我认为,如果你想找到完全排列的中位数,那就有好消息和坏消息:好消息:似乎有一个简单的算法。坏消息:没有确切的中位数,因为排列的数量总是均匀的(因为它是1 x 2 x 3 x ... x n)
对于您的示例:12345 - &gt; 3 1245 - &gt; 3 2 145 - &gt; 32 541 ,或12345 - &gt; 3 1245 - &gt; 3 4 125 - &gt; 34的 125 强>
这背后的直觉如下:您可以将 n 数字的 n!(已排序)排列细分为 n 组,每个组以 ith 数字开头并具有(n-1)!元素。由于这些组是有序的,并且每个组具有相同数量的元素,因此中位数必须位于奇数编号输入的中间组中,而位于中间的两组之间用于偶数 - 编号输入。因此,您必须选择较大或较小的较大中间组中最大的一个。 (对于奇数编号的输入,对中间组的 n-1 子组执行相同操作。)
这是一个示例代码(在Python中,因为我太懒了......)
# above algorithm
def med_perm(n):
lst = sorted(str(n)) # step 1
res = [lst.pop(len(lst)//2)] if len(lst) % 2 == 1 else [] # step 2
res.append(lst.pop(len(lst)//2)) # step 3
res.extend(lst) # step 4
return int(''.join(res))
# for reference
import itertools
def med_perm2(n):
perms = list(map(''.join, itertools.permutations(sorted(str(n)))))
return int(perms[len(perms)//2])
# testing
import random
n = random.randint(1, 100000000)
x, y = med_perm(n), med_perm2(n)
print(n, x, y, x==y)
答案 1 :(得分:0)
我实际上找到了一个偷偷摸摸的方法来做到这一点。我把所有东西写在纸上,并认出了一种模式。这是代码的第一个草案,它可能更有效地完成。随意调整!
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Kata {
public static String findMidPerm(String strng) {
strng = sortString(strng);
StringBuilder sb = new StringBuilder();
List<Integer> s = createNum(strng);
for(int i =0; i <s.size(); i++) {
int b = s.get(i);
sb.append(strng.charAt(b-1));
}
return sb.toString();
}
private static String sortString(String strng) {
char[] ar = strng.toCharArray();
Arrays.sort(ar);
String sorted = String.valueOf(ar);
return sorted;
}
public static List<Integer> createNum(String strng) {
List<Integer> list = new ArrayList<>();
int s = strng.length() / 2;
int s2 = (strng.length() / 2) + 1;
if (strng.length() % 2 == 0) {
list.add(s);
for (int i = strng.length(); i > 0; i--)
if (i != s) {
list.add(i);
}
} else {
list.add(s2);
list.add(s);
for (int i = strng.length(); i > 0; i--)
if (i != s && i != s2) {
list.add(i);
}
}
return list;
}
public static void main(String[] args) {
System.out.println(findMidPerm("cmafilezoysht")); // cmafilezoysht is an input string in this case.
}
}