[访谈]找出正整数排列的任何排列可以形成的最大值

时间:2013-06-28 10:59:34

标签: algorithm sorting

给定一组正整数,找到可以通过排列的任何排列形成的最大值。我想知道是否有更好的数据结构可以为问题提供更优雅的解决方案。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


public class FindMaximumNumbersFromPermutation {


    static class DS implements Comparable<DS> {

        int intAtI;
        Integer[] actualInt;

        public DS(int intAtI, Integer[] actualInt) {
            super();
            this.intAtI = intAtI;
            this.actualInt = actualInt;
        }

        @Override
        public int compareTo(DS o) {
            if(intAtI < o.intAtI)
                return 1;
            else if(intAtI == o.intAtI)
                return 0;
            else return -1;
        }

        @Override
        public String toString() {
            String s="";
            for(int i=0;i<actualInt.length;i++)
                s= s+actualInt[i];
            return s;
        }
    }

    public static void main(String[] args)
    {
        int[] arr = {21,9,23};

        List<Integer[]> list = new ArrayList<Integer[]>();
        int maxLength= 0;
        for(int i=0;i<arr.length;i++)
        {
            Integer[] digitsArray = getDigitsArray(arr[i]);
            if(digitsArray.length > maxLength)
                maxLength = digitsArray.length;
            list.add(digitsArray);
        }


        List<Integer[]> output = new ArrayList<Integer[]>();
        for(int currentLength=0;currentLength<=maxLength;currentLength++)
            doWork(list, output, currentLength);

        for(int i=0;i<output.size();i++)
        {
            Integer[] temp = output.get(i);
            for(int j=0;j<temp.length;j++)
            {
                System.out.print(temp[j]);
            }
        }

    }

    private static void doWork(List<Integer[]> list, List<Integer[]> output,
            int currentLength) {
        List<DS> dsList = new ArrayList<DS>();

        for(int i=0;i<list.size();i++)
        {
            Integer[] temp = list.get(i);
            if(temp.length>currentLength)
            {
                dsList.add(new DS(temp[currentLength],temp));
            }
        }

        Collections.sort(dsList);
        Map<Integer,List<Integer[]>> map = new TreeMap<Integer,List<Integer[]>>();

        for(int i=0;i<dsList.size();i++)
        {
            DS  ds = dsList.get(i);
            if(!map.containsKey(ds.intAtI))
            {
                List<Integer[]> l = new ArrayList<Integer[]>();
                l.add(ds.actualInt);
                map.put(ds.intAtI, l);
            }
            else
            {
                List<Integer[]> l = map.get(ds.intAtI);
                l.add(ds.actualInt);
                map.put(ds.intAtI, l);
            }
        }

        ArrayList<Integer> keys = new ArrayList<Integer>(map.keySet());
        for(int i=keys.size()-1;i>=0;i--)
        {
            Integer key = keys.get(i);
            List<Integer[]> l = map.get(key);
            if(l.size() ==1)
                output.add(l.get(0));
        }


    }

    static Integer[] getDigitsArray(int integer)
    {
        String s = integer+"";
        Integer[] ret = new Integer[s.length()];
        for(int i=0;i<s.length();i++)
        {
            ret[i] = Integer.parseInt(s.charAt(i)+"");
        }

        return ret;
    }
}

3 个答案:

答案 0 :(得分:3)

一般情况(将任意非负整数粘合在一起,不一定是数字),恕我直言,非常有趣,例如

 [709, 8, 70, 71, 5, 7] -> 8771709705
 [31, 34, 30, 3]        -> 3433130
 [334, 323, 30, 31, 3]  -> 33433233130

这个想法与提到的H2CO3相同:数组排序, 但实现(C#)是不同的

private static int Compare(int x, int y) {
  if (x == y)
    return 0;

  // Not that good solution (to compare chars), but easy to implement
  String Stx = x.ToString(CultureInfo.InvariantCulture);
  String Sty = y.ToString(CultureInfo.InvariantCulture);

  int n = Stx.Length < Sty.Length ? Stx.Length : Sty.Length;

  // Standard lexicographic comparison: 9 > 80, 293 > 2896, 9873 > 986 etc.
  for (int i = 0; i < n; ++i)
    if (Stx[i] > Sty[i])
      return 1;
    else if (Stx[i] < Sty[i])
      return -1;

  // Special case: ab <>= a? 
  // 70 < 7; 78 > 7 etc
  if (Stx.Length > Sty.Length) {
    for (int i = n; i < Stx.Length; ++i)
      if (Stx[i - 1] > Stx[i])
        return -1;
      else if (Stx[i - 1] < Stx[i])
        return 1;
  }
  else {
    for (int i = n; i < Sty.Length; ++i)
      if (Sty[i - 1] > Sty[i])
        return 1;
      else if (Sty[i - 1] < Sty[i])
        return -1;
  }

  return 0;
}

然后

int[] data = new int[] { 709, 8, 70, 71, 5, 7 };
Array.Sort(data, Compare);

StringBuilder Sb = new StringBuilder();

for (int i = data.Length - 1; i >= 0; --i)
  Sb.Append(data[i]);

// 8771709705
String result = Sb.ToString();

答案 1 :(得分:1)

假设“正整数”是数字(考虑到排列的这个约束,对我来说没有其他意义),解决方案很简单:对整数数组进行排序,最大数字的第一个数字将是最大数字,第二个是第二大等,例如,给定一个数字数组1 5 7 3,排序的数组是7 5 3 1,所以最大的这个数字是7531.排序可以在{ {1}},or even in O(n)

编辑:如果数字不限制为单个数字,则从每个数字中提取所有数字,删除重复项并将它们添加到数组中,然后使用该数组执行排序等操作现在开始。

C ++演示:

O(n log n)

And it works, even with numbers with zeroes in them.

修改2:如果您不需要数字是唯一的,那么请使用向量而不是集合:

#include <iostream>
#include <map>
#include <sstream>
#include <set>

#define COUNT(a) (sizeof(a) / sizeof((a)[0]))

void add_digits(std::set<int> &digits, int n)
{
    if (n == 0) {
        digits.insert(0);
    } else {
        while (n) {
            digits.insert(n % 10);
            n /= 10;
        }
    }
}

int main()
{
    int nums[] = { 21, 9, 23 };

    std::set<int> digits;
    for (int i = 0; i < COUNT(nums); i++)
        add_digits(digits, nums[i]);


    std::cout << "The largest number is ";
    for (std::set<int>::reverse_iterator it = digits.rbegin(); it != digits.rend(); it++)
        std::cout << *it;

    std::cout << std::endl;
    return 0;
}

答案 2 :(得分:1)

假设您有一些1位数字,一些2位数,3位数,......,r位数。

按编号对您的数字分组为r列表,并对每个列表进行排序。在每一步中,您追加的数字将是其中一个列表的最大元素,因此如果数字集相对于r大,这将有所帮助。

,例如,[1,2,21,33,94,9,88] =&gt; [9,2,1]和[94,88,33,21]

9  [2,1][94, 88, 33, 21]
994 [2,1][88, 33, 21]
99488 [2,1][33,21]
9948833 [2,1][21]
99488332 [1][21]
9948833221 [1]
99488332211 [] done

接下来,您需要一种有效的方法从列表顶部的数字中选择正确的数字。

以最短的数字开头,按照位数的升序浏览列表头部的数字。存储您当前的候选人(最初是最短数字列表的头部)。如果您当前的候选K有k个数字,并且您正在与具有s> k个数字的数字S进行比较,请考虑S的前k个数字。如果该数字大于K,则将S作为您的候选者。如果小于K,则跳过S。

唯一棘手的案例是他们是否平等。然后,比较该对可以进入的两个订单,并选择在两个中较大的一个中作为您的候选者的那个。我相信如果他们是平等的,那么选择是任意的,但却没有说服自己。