找到一个给定数字附近的数字

时间:2017-11-07 14:08:47

标签: java algorithm

我有一个数字(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的整数的顺序。有没有人有任何想法如何实现这一目标?

2 个答案:

答案 0 :(得分:1)

(这是原始问题的答案,如何找到所有排列的中位数,而不是XY问题,如何找到最接近给定数字的排列。)

我认为,如果你想找到完全排列的中位数,那就有好消息和坏消息:好消息:似乎有一个简单的算法。坏消息:没有确切的中位数,因为排列的数量总是均匀的(因为它是1 x 2 x 3 x ... x n)

  1. 对输入数字进行排序,使数字按升序排列
  2. 如果数字的位数为奇数,则选择中间数字作为第一个数字
  3. 这个数字现在有一个偶数位数;你必须选择两个中间数字中的任何一个,但这会使结果出现偏差(见上面的坏消息)
  4. 如果您选择了中间较低的数字,请从剩余数字中形成最大可能的数字,否则最低可能的数字。
  5. 对于您的示例: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.

}

}