如何操作数组以获得最大数量?

时间:2011-02-18 04:09:25

标签: arrays algorithm

假设你有一个正整数数组,操纵它们,以便结果数组的整数串联是可能的最大数。 例如:{9,1,95,17,5},结果:9955171

家庭作业警察:这是一个谷歌电话采访问题,并没有签署任何NDAs;)。

17 个答案:

答案 0 :(得分:34)

正如其他人所指出的那样,词典排序和连接很接近,但并不完全正确。例如,对于数字55456,词典排序将产生 {5,54,56} (按递增顺序)或< strong> {56,54,5} (按降序排列),但我们真正想要的是 {56,5,54} ,因为这会产生尽可能多的数字。

所以我们想要一个两个数字的比较器,以某种方式将最大数字放在第一位。

  1. 我们可以通过比较两个数字的个别数字来做到这一点,但是如果另一个数字仍然有剩余的数字,我们必须小心我们离开一个数字的结尾。我们必须要有很多计数器,算术和边缘情况。
  2. 一个可行的解决方案(也由@Sarp Centel提到)实现与(1)相同的结果,但代码少得多。我们的想法是将两个数字的串联与这些数字的反向连接进行比较。我们必须在(1)中明确处理的所有残余都是隐式处理的。

    例如,为了比较565,我们会对565556进行常规的词典比较。自565&gt; 556,我们会说565“更大”,应该先行。同样,比较545意味着我们将测试545&lt; 554,告诉我们554“更大”。

  3. 这是一个简单的例子:

    // C++0x: compile with g++ -std=c++0x <filename>
    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <vector>
    
    int main() {
      std::vector<std::string> v = {
        "95", "96", "9", "54", "56", "5", "55", "556", "554", "1", "2", "3"
      };
      std::sort(v.begin(), v.end(),
          [](const std::string &lhs, const std::string &rhs) {
            // reverse the order of comparison to sort in descending order,
            // otherwise we'll get the "big" numbers at the end of the vector
            return rhs+lhs < lhs+rhs;
          });
    
      for (size_t i = 0; i < v.size(); ++i) {
        std::cout << v[i] << ' ';
      }
    }
    

    运行时,此代码显示:

    9 96 95 56 556 5 55 554 54 3 2 1
    

答案 1 :(得分:10)

查看示例{5,54,56},订购这些数字的正确方法是在比较字符串A和B时,我们应该考虑A + B与B + A的字典排序。

例如:

  • 比较(5,54)成为(“554”与“545”)的词典对照
  • 比较(5,56)成为(“556”与“565”)的词典对照
  • 比较(54,56)成为(“5456”与“5654”)的词典对照

如果我们按这种方式对它们进行排序,结果数组为{56,5,54}。

这是这个想法的Java实现:

public class LexicographicSort implements Comparator<Integer> {

    public int compare(Integer o1, Integer o2) {
        String s1 = o1.toString();
        String s2 = o2.toString();
        return (s2+s1).compareTo(s1+s2);
    }

    public static void main(String[] args) {
        LexicographicSort ls = new LexicographicSort();
        Integer[] nums = {9,1,95,17,5};
        Arrays.sort(nums, ls);
        System.out.println(Arrays.toString(nums));
    }
}

答案 2 :(得分:6)

好吧,你可以试试这个

  • 将数字拆分为单个字符
  • 按字典顺序按降序排序
  • 列出清单

你的号码最多

答案 3 :(得分:3)

这是c ++中的实现

#include <stdio.h>
#include <sstream>

using namespace std;

/**
    a = 123
    b = 15
    v1 = 12315
    v2 = 15123
    return (v2 - v1) to make the function sort in descending order
*/
int compare_concatenated_ints(const void *arg1, const void *arg2)
{
    int v1 = *(int*) arg1;
    int v2 = *(int*) arg2;

    stringstream s1, s2;
    s1 << v1 << v2;
    s2 << v2 << v1;

    s1 >> v1;
    s2 >> v2;

    return (v2 - v1);
}

void print_array(int arr[], int count)
{
    for (int i = 0; i < count; ++i){
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main()
{
    int arr[] = {4, 0, 94, 9, 14, 0, 1};    
    int count = sizeof(arr)/sizeof(arr[0]);

    printf("BEFORE\n");
    print_array(arr, count);

    std::qsort(arr, count, sizeof(int), compare_concatenated_ints);

    printf("AFTER\n");
    print_array(arr, count);
}

答案 4 :(得分:2)

我想它已经解决了。使用几个答案中已经讨论过的逻辑,Python中有几行代码:

>>li = [9,1,95,17,5]
>>li.sort(cmp=lambda a,b: cmp(int(str(a)+str(b)), int(str(b) + str(a))), reverse=True)

>>output = ""
>>for i in li:
output += str(i)

>>print  output

答案 5 :(得分:2)

不确定是否有人在寻找JavaScript解决方案,但是如果您正在寻找,这里是代码

function LexicographicSort(input) {
    return Number(
        input
            .sort(function(a, b) {
// lexicographic sort
               return Number("" + b + a) - Number("" + a + b);
            })
            .join("")
        );
}

答案 6 :(得分:1)

@Nate Kohl的想法非常好。我刚刚使用quicksort实现了Java版本。这是:

import java.util.Random;

public class Sort_MaxConcatenation {
    private Random r = new Random();

    public void quicksort_maxConcatenation(int[] a, int begin, int end) {
        if (begin < end) {
            int q = partition(a, begin, end);
            quicksort_maxConcatenation(a, begin, q);
            quicksort_maxConcatenation(a, q + 1, end);
        }
    }

    private int partition(int[] a, int begin, int end) {
        int p = begin + r.nextInt(end - begin + 1);
        int t1 = a[p];
        a[p] = a[end];
        a[end] = t1;

        int pivot = t1;
        int q = begin;
        for (int i = begin; i < end; i++) {
            if (compare_maxConcatenation(a[i], pivot) > 0) {
                int t2 = a[q];
                a[q] = a[i];
                a[i] = t2;
                q++;
            }
        }
        int t3 = a[q];
        a[q] = a[end];
        a[end] = t3;

        return q;
    }

    private int compare_maxConcatenation(int i, int j) {
        int ij = Integer.valueOf(String.valueOf(i).concat(String.valueOf(j)));
        int ji = Integer.valueOf(String.valueOf(j).concat(String.valueOf(i)));
        if (ij > ji)
            return 1;
        else if (ij == ji)
            return 0;
        return -1;
    }

    public static void main(String[] args) {

        int[] a = new int[]{56, 5, 4, 94, 9, 14, 1};
        Sort_MaxConcatenation smc = new Sort_MaxConcatenation();
        smc.quicksort_maxConcatenation(a, 0, a.length-1);
        for(int i = 0;i < a.length;i++) {
            System.out.print(a[i]);
        }
    }
}

答案 7 :(得分:0)

有趣的问题。我想你可以先用最简单的方法开始,这将使用强力来使用递归创建所有可能的数字(取决于问题和语言,这可能必须改为迭代)并跟踪哪一个是最大的。例如{1,83,91}会给你{18391,19183,83191,83911,91183,91831},你可以从中确定91831为最大数字。

使用对原始数字进行排序并按顺序连接数字的解决方案有一个缺陷,如果你有类似{9,82,99}的东西,那么排序的数组将是{99,82,9}。但是,这将导致99829,而最大数字实际上是99982。

由于蛮力解决方案有效,但在性能方面可能不是最佳,因此最好找出优化解决方案的方法(当然,在分析原始解决方案之后)。例如,您可以从简单的排序方案开始,将数字的各个数字乘以它们占据的位置。

{ 9, 98, 95 }

上述设置将产生一个5位数字。我们将应用一个简单的公式,将个别数字乘以其位置(1表示1位,2表示10位数等)并将它们相加如下:

9 -> 9 * 5
98 -> 9 * 5 + 8 * 4
95 -> 9 * 5 + 5 * 4

导致

9 -> 45
98 -> 77
95 -> 65

现在,作为人类,我们知道9应首先出现,而不是98或95.解决这个问题的一种方法是,如果候选人的第一个数字是相同的(即支持9或95分之98/等)。如果左边的数字较大或等效(如果数字的数量相等,则使用上面的公式),你可以选择每次数较少的候选者。如果我们有{9871,986},那么9871会有更高的值,但我们会看986并看到它的数字更少。

9 8 7 1
| | | |
9 8 6

8场比赛,继续,7场更大,所以忽略986(9871986对比较小的9869871)。如果该集合是{9861,987}而不是:

9 8 6 1
| | | |
9 8 7

8场比赛,继续,7场更大,所以选择987(9879861对比较小的9861987)。

所以使用以下集合测试:

{ 7, 61, 811, 99 }

结果将是一个8位数字。应用展示位置公式可以得到:

7 -> 7 * 8 = 56
61 -> 6 * 8 + 1 * 7
811 -> 8 * 8 + 1 * 7 + 1 * 6 = 77
99 -> 9 * 8 + 9 + 7 = 135

所以99看起来会先行,但现在让我们通过选择数字较少的数字来应用算法的第二部分:

7
当然,

7与9不相同,所以我们留下99作为第一个数字。

9 9 _ _ _ _ _

下一次迭代:

7 -> 7 * 6 = 42
61 -> 6 * 6 + 1 * 5 = 41
811 -> 8 * 6 + 1 * 5 + 1 * 4 = 57

811具有最高值,并且61和7从左到右没有相同的数字,因此我们插入811。

9 9 8 1 1 _ _ _

下一次迭代:

7 -> 7 * 3 = 21
61 -> 6 * 3 + 1 * 2 = 20

7具有更高的值,没有更少的数字 - 插入:

9 9 8 1 1 7 _ _

下一次迭代:

只剩下一个数字(61),所以我们将其插入

9 9 8 1 1 7 6 1 -> 99811761

获得最大数量!请注意,如果61是81之类的东西,它会在811的位置正确结束 - &gt; 99818117而不是错误的99811817。

答案 8 :(得分:0)

这是我的解决方案,虽然它可能效率不高。代码在python1.3

#! /usr/bin/env python

def sort(arr):
    temparr = []
    for num in arr:
        l = len(str(num)) - 1
        n = num / pow(10, 1)
        temparr.append((n, num))
    temparr.sort()
    temparr.reverse()
    return [t[1] for t in temparr]

def buildNum(arr):
    finalNum = None
    for num in arr:
        snum = str(num)
        if not finalNum:
            finalNum = snum
        else:
            n1 = finalNum + snum
            n2 = snum + finalNum
            if n1 >= n2:
                finalNum = n1
            else:
                finalNum = n2
    return finalNum

def main():
    arr = [9,1,95,17,5]
    arr = sort(arr)
    print buildNum(arr)
main()

答案 9 :(得分:0)

我的策略是使用任何排序算法和自定义比较功能。

在深入研究代码之前,需要考虑以下几点:

如果位数相等,则比较是直接的。 但是如果数字的位数不相等,那么我们用更多的位数提取整数的最左边的数字(然后递归地比较)。

代码说明最好。所以,这是我的工作代码:

int numDigits(int number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

int comparator ( const void * elem1, const void * elem2 )
{
    int x = *(int *)elem1;
    int y = *(int *)elem2;

    if(x==y) return 0;

    int xLen = numDigits(x);
    int yLen = numDigits(y);

    if(xLen==yLen)
    {
        return x>y ? -1 : +1;
    }
    else
    {
        int xTens = pow((double)10,(double)xLen-1);
        int yTens = pow((double)10,(double)yLen-1);
        int xLeftmostDigit = (xTens != 0) ? x/xTens : 0;
        int yLeftmostDigit = (yTens != 0) ? y/yTens : 0;

        if( xLeftmostDigit == yLeftmostDigit )
        {
            if(xLen<yLen)
            {
                int yStrippedOutOfLeftmostDigit = y - yLeftmostDigit*yTens;
                return comparator(&x, &yStrippedOutOfLeftmostDigit);
            }
            else
            {
                int xStrippedOutOfLeftmostDigit = x - xLeftmostDigit*xTens;
                return comparator(&xStrippedOutOfLeftmostDigit, &y);
            }
        }
        else
        {
            return xLeftmostDigit > yLeftmostDigit ? -1 : +1;
        }
    }
    return false;
}

我专门编写了上面的函数,用于stl的qsort。

这是我的测试代码:

int main(int argv,char **argc) {
    //Ex: {9,1,95,17,5}, result: 9955171 

    int arr[] = {9,1,95,17,5};
    int arrLen = 5;

    for(int i=0; i<arrLen; i++)
    {
        cout << arr[i] << "_" ;
    }
    cout << endl;

    qsort(arr, 5, sizeof(int), comparator);

    for(int i=0; i<arrLen; i++)
    {
        cout << arr[i] << "_" ;
    }
    cout << endl;
}

答案 10 :(得分:0)

编辑:

创建一个数组,其中包含初始数组的所有可能的连接

你得到:

{91 , 19}合并1和9

当9和95

时,

{995 , 959}

{917 , 179}时9和17

来自所有这些元组的

获得更高的数字。并从数组中删除用于生成该concat字符串的数字,并从元组中删除使用这些数字的所有concats,以避免明显的错误。找到元组中的下一个大数字......等等......


我对如何解决这个问题有一个大概的了解,但我不知道如何使其适用于任何其他大于2位数的数字,也许这会对你有帮助。

{9,1,95,17,5}

确定将数组拆分为两个数组,其中一个包含一位数字,另一个包含两位数。

对它们进行排序

您获得{95 , 17}{9,5,1}

比较A1 [0] + A2 [0]&gt; A2 [0] + A1 [0]按字典顺序, 例如959> 995 ??? (在这种情况下+不是数学加法,而是字符串连接)

并获得更大的那两个

然后你留下了995和{17}以及{5,1} 再次,175&gt; 517?

您获得了995-517,而您将获得{1}

希望有所帮助

答案 11 :(得分:0)

在C#中

static void Concat(params int[] array)
{
    List<int> values = new List<int>(array);
    values.Sort((a, b) =>
        {
            StringBuilder asb = new StringBuilder(a.ToString());
            StringBuilder bsb = new StringBuilder(b.ToString());

            int lengthDiff = asb.Length - bsb.Length;

            if (lengthDiff == 0)
                return -a.CompareTo(b);
            else if (lengthDiff > 0)
                bsb.Append(bsb[bsb.Length - 1], lengthDiff);
            else
                asb.Append(asb[asb.Length - 1], -lengthDiff);

            return -asb.ToString().CompareTo(bsb.ToString());
        });

如果你对符号扩展位比较熟悉,你可以看到这只是相反的情况。它将较短长度的数字的最后一个数字扩展到相同的长度,它们只返回字符串比较。

答案 12 :(得分:0)

我会使用以下函数对它们进行排序

class Kakira {

    static int preferred(int a, int b) {
        if(a == b) return a; // doesn't matter which
        String sa = a+"";
        String sb = b+"";

        for(int i = 0; i < sa.length() && i < sb.length(); i++) {
            char ca = sa.charAt(i);
            char cb = sb.charAt(i);
            if(ca < cb) return b;
            if(ca > cb) return a;
        }
        // we reached here - the larger one must start with the smaller one
        // so, remove the small one from the start of the small one, and
        // that will tell us which is most appropriate.
        if(a < b) {
            String choppedB = sb.substring(sa.length());
            if(preferred(Integer.parseInt(choppedB),a) == a) 
                return a;
            else
                return b;
        }
        else {
            String choppedA = sa.substring(sb.length());
            if(preferred(Integer.parseInt(choppedA),b) == b) 
                return b;
            else
                return a;
        }
    }

    // using a very simple sort because I'm being lazy right now
    public static void sort(int[] data) {
        while(!isSorted(data)) {
            for(int i = 0; i < data.length - 1; i++) {
                int a = data[i];
                int b = data[i+1];
                int p = preferred(a,b);
                if(p == b) {
                    data[i] = b;
                    data[i+1] = a;
                }
            }
        }
    }

    public static boolean isSorted(int[] data) {
        for(int i = 0; i < data.length - 1; i++) {
            int a = data[i];
            int b = data[i+1];
            int p = preferred(a,b);
            if(p != a) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        int[] data = new int[]{9,1,95,17,5};
        sort(data);
        for(int i : data) System.out.print(i);
        System.out.println("");
    }

}

对于人类: 首先:我将使用特殊的比较功能对它们进行排序。这将使它们按照最理想的顺序排列,因此我们可以将它们打印出来。

我并不担心排序算法,因为一旦你进行了比较,就可以使用你想要的任何排序。比较是重要的部分。

让我们来看看决策过程。

首先,如果两个数字相等,那么没有人关心它是哪一个。所以我们回来吧。

接下来,我们得到数字的字符串表示,以便我们可以开始比较数字。 我们沿着数字向下走,直到我们用完其中一个字符串上的数字。一旦它们不再相等,我们想要一个具有更大价值的那个,因为我们想要早期获得高位数(我认为这显然是为什么)。

如果我们到达其中一个数字的末尾并且我们还没有获胜者,我们知道必须从较短的数字开始。它们的长度不能相等,因为如果第一个数字相等,并且它们的长度相等,则数字本身是相等的,并且它们将在此过程中被捕获。所以问题是,哪一个先行?好吧,考虑一下后果:

12345 first: 12345123
123 first: 12312345

显然我们想要第一个。但是怎么知道这个?我们从长路上取123。所以我们有45和123。

现在,再次通过算法运行这些算法,确定哪个是赢家,并且赢得第二轮的任何一个也赢得了第一轮。如果要更深入,请说(12312312和123)然后它会继续下降。

有意义吗?

答案 13 :(得分:0)

好的,这个算法怎么样,它使用比较函数来检查前一个数字和下一个索引中的数字。为了简单起见,我使用了字符串而不是整数。虽然算法很好地解释了它在做什么

  #include<string>
  #include<iostream>
  #include<algorithm>
  using  namespace std;

  int main(){
  bool arranged=false;
  string arr[]={"98","12","56","9"};
  for(int i=0;i<4;i++)
    cout<<arr[i]<<" ";
    cout<<endl;

while( arranged==false )
{ 
string previous = arr[0];
  arranged = true;
  for(int i = 1; i < 4;i++)
  { 
    string  XY = (previous + arr[i] ); 
    string  YX = (arr[i] + previous);        
      if ( YX.compare(XY) > 0 ) {
     swap(arr[i],arr[i-1]);
     arranged = false;
    }
   previous = arr[i];  
    }
 }

   for(int i=0;i<4;i++)
   cout<<arr[i];

   return 0;
 }  

答案 14 :(得分:0)

这是java中的简单实现,不使用比较器

import java.util.List;

import java.util.ArrayList;

import java.util。*;

import java.lang.Math;

公共类LargestNumber {

public static void main(String args[]){
    ArrayList<Integer> al = new ArrayList<Integer>(); 
    al.add(872);
    al.add(625);
    al.add(92);
    al.add(8);
    al.add(71);

    Find find = new Find();
    find.duplicate(al);
    }

}

课程查找{

public void duplicate(ArrayList<Integer> al){
    String numL ="";
    int size = al.size();
    Collections.sort(al,Collections.reverseOrder());
    ArrayList<Integer> arrL = new ArrayList<Integer>();
    for(int i = 0; i < size; i++){
        for(int j = 0; j < size - 1; j++){
            if((compare(al.get(j), al.get(j+1))) == 1){
                Collections.swap(al,j,j+1);
            }
        }
    }

    for(int i = 0; i < size; i++){
        numL = numL + al.get(i);
    }
    System.out.println(numL);

}

public static int compare(int x, int y){

    String xStr = String.valueOf(x);
    String yStr = String.valueOf(y);

    int a = Integer.parseInt(xStr+yStr);
    int b = Integer.parseInt(yStr+xStr);

    return (a>b)? 0:1;
}

}

<强>输出 92887271625

答案 15 :(得分:0)

这是Python 3解决方案,其中a是一个数组,n是元素的总数

def check(p,q):
    p=str(p)
    q=str(q)
    d=max(p+q,q+p)
    if d==p+q:
        return int(p),int(q)
    else:
        return int(q),int(p)
def find(a,n):
    for i in range(n):
        for j in range(n-1):
            c,d=check(a[j],a[j+1])
            a[j]=c
            a[j+1]=d
    print(*a,sep="")

答案 16 :(得分:0)

这是一个非常简单的 C 代码,n 在 1-100 范围内:

#include<stdio.h>
#include<math.h>

int main()
{
   int n;
   int arr[101];
   scanf("%d", &n);
   for (int i = 0; i < n; i++)
       scanf("%d", &arr[i]);
   for (int i = 0; i < n; i++)
   {
       for (int j = i + 1; j < n; j++)
       {
           int a = arr[i];
           int b = arr[j];
           int num_of_digits_a = 0;
           if (a == 0)
           {
               num_of_digits_a = 1;
           }
           else
           {
               while (a != 0)
               {
                   a /= 10;
                   num_of_digits_a++;
               }
           }
           int num_of_digits_b = 0;
           if (b == 0)
           {
               num_of_digits_b = 1;
           }
           else
           {
               while (b != 0)
               {
                   b /= 10;
                   num_of_digits_b++;
               }
           }
           long long int firstPossibility = pow(10, num_of_digits_a) * arr[j] + arr[i];
           long long int secondPossibility = pow(10, num_of_digits_b) * arr[i] + arr[j];
           if (firstPossibility > secondPossibility)
           {
               int temp = arr[i];
               arr[i] = arr[j];
               arr[j] = temp;
           }
       }
   }
   for (int i = 0; i < n; i++)
       printf("%d", arr[i]);
   return 0;
}