Say you have an array of positive integers, manipulate them so that the concatenation of the integers of the resultant array is the largest number possible. Ex: {9,1,95,17,5}, r
I guess it has already been solved. Here are few lines of code in Python using the logic already discussed in few of the answers:
>>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
Edit:
Create an array which contains all possible concats of the initial array
You get :
{91 , 19}
When combining 1 and 9
{995 , 959}
when 9 and 95
{917 , 179}
when 9 and 17
from all those tuples get the higher number. and remove from the array the numbers that were used to make that concat string, and from the tuples remove all concats that use those numbers so as to avoid obvious mistake. Find the next big number in the tuples etc... etc...
I have a general idea as to how I would go about this, but I am not sure how to make it work for any other numbers bigger than 2 digits, maybe this will help you.
{9,1,95,17,5}
ok split the array into two arrays with one holding single digit numbers, and one holding the two digits.
sort them
you get {95 , 17}
and {9,5,1}
compare if A1[0]+A2[0] > A2[0]+A1[0] lexicographically,
eg 959 > 995 ??? (+
in this case is not mathematical addition but string concat)
and get the bigger of those two
then you are left with 995 and {17}
and {5,1}
again, 175 > 517 ?
you get 995-517 and you are left with {1}
Hope that helps
In 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());
});
If you're familier with sign-extending bits, you can see this does exactly that only in reverse. It extends the shorter length number's last digit out to the same length and them simply returns the string comparison.
The idea of @Nate Kohl is very good. I just implemented a Java version using quicksort. Here it is:
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]);
}
}
}
#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);
}
My strategy is to use any sorting algorithm with a custom compare function.
Before we dive into the code, here are some things to consider:
If the number of digits are equal, then the comparison is straight forward. But if the number of digits are unequal, then we extract the leftmost digit of the integer with more number of digits (and then compare recursively).
Code explains best. So, here is my working code:
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;
}
I wrote the above function specifically to be used with the stl's qsort.
This is my test code:
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;
}