3

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

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;
    }
}
4

3 回答 3

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();
于 2013-06-28T11:36:33.800 回答
1

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

按位数将您的数字分组到 r 个列表中,并对这些列表中的每一个进行排序。在每一步,您附加的数字将是这些列表之一的最大元素,因此如果数字集相对于 r 较大,这将有所帮助。

例如,[1,2,21,33,94,9, 88] => [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。

唯一棘手的情况是它们是否相等。然后,比较这对可能进入的两个订单,并选择两个订单中较大的一个作为您的候选人。我相信如果他们是平等的,选择是任意的,但我没有说服自己。

于 2013-06-28T20:58:56.430 回答
1

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

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

C++ 演示:

#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:如果您不需要数字是唯一的,则使用向量而不是集合:

#include <iostream>
#include <vector>

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

void add_digits(std::vector<int> &digits, int n)
{
    if (n == 0) {
        digits.push_back(0);
        return;
    }

    while (n) {
        digits.push_back(n % 10);
        n /= 10;
    }
}

bool intcmp(const int &lhs, const int &rhs)
{
    return lhs > rhs;
}

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

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


    std::sort(digits.begin(), digits.end(), intcmp);

    std::cout << "The largest number is ";
    for (std::vector<int>::iterator it = digits.begin(); it != digits.end(); it++)
        std::cout << *it;

    std::cout << std::endl;
    return 0;
}
于 2013-06-28T11:04:08.070 回答