【问题标题】:[Interview]Find the max no that can be formed by any permutation of the arrangement of positive integers[采访]求正整数排列的任意排列可以形成的最大数
【发布时间】:2013-06-26 03:16:20
【问题描述】:

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

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

【问题讨论】:

  • 您只是...将数组从大到小排序?这将永远是最大的数字。
  • @SBI 几乎是的......
  • @SBI 这不会起作用,因为 {21,9,23} 会用你的方法给出 23219,而正确的答案应该是 92321
  • 有一个简单的字典排序算法的反例:[32, 321] -> 32, 321 while [32, 324] -> 324, 32
  • this question 中有几种方法(在 Python 中,但很容易转换)。

标签: algorithm sorting


【解决方案1】:

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

 [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();

【讨论】:

    【解决方案2】:

    假设您有一些 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。

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      编辑 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;
      }
      

      【讨论】:

      • 我不相信这些数字被限制为个位数。代码中的示例是 21,9,23,您的算法会将 23219 的数字排序为 23,21,9,但更好的排列是 9,23,21,因为 92321 大于 23219。
      • 考虑到您正在拆分多位数字,据我所知,这是不希望的。无论如何:7,13,3,1,最大的数字是73131,并且指出,这不仅仅是从高到低的排序。如果你的意思是,“每个数字的最高第一位”会更清楚。然后按降序排列。如果有两个数字相同,请先使用任何多位数字。
      • @PeterdeRivaz 是的。我认为我们需要对每个数字进行排序并打印结果。唯一我不确定的是最好的 DS 用于此
      • 在每个数字或每个数字上?这有很大的不同。
      • @PeterdeRivaz 我已经相应地更新了我的答案,你现在可以撤销你的反对票。
      猜你喜欢
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      • 2012-08-17
      相关资源
      最近更新 更多