假设你有一个正整数数组,操纵它们,以便结果数组的整数串联是可能的最大数。 例如:{9,1,95,17,5},结果:9955171
家庭作业警察:这是一个谷歌电话采访问题,并没有签署任何NDAs;)。
答案 0 :(得分:34)
正如其他人所指出的那样,词典排序和连接很接近,但并不完全正确。例如,对于数字5
,54
和56
,词典排序将产生 {5,54,56} (按递增顺序)或< strong> {56,54,5} (按降序排列),但我们真正想要的是 {56,5,54} ,因为这会产生尽可能多的数字。
所以我们想要一个两个数字的比较器,以某种方式将最大数字放在第一位。
一个可行的解决方案(也由@Sarp Centel提到)实现与(1)相同的结果,但代码少得多。我们的想法是将两个数字的串联与这些数字的反向连接进行比较。我们必须在(1)中明确处理的所有残余都是隐式处理的。
例如,为了比较56
和5
,我们会对565
到556
进行常规的词典比较。自565
&gt; 556
,我们会说56
比5
“更大”,应该先行。同样,比较54
和5
意味着我们将测试545
&lt; 554
,告诉我们5
比54
“更大”。
这是一个简单的例子:
// 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的字典排序。
例如:
如果我们按这种方式对它们进行排序,结果数组为{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)
#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
{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;
}