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
Here is the simple implementation in java without using comparator
import java.util.List;
import java.util.ArrayList;
import java.util.*;
import java.lang.Math;
public class 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);
}
}
class Find{
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;
}
}
Output 92887271625
Interesting question. I suppose you could start with the simplest approach first, which would use brute force to create all possible numbers using recursion (depending on the problem & language this might have to be changed to iteration) and keep track of which one is the largest. For example {1, 83, 91} would give you { 18391, 19183, 83191, 83911, 91183, 91831 } from which you could determine 91831 as the largest number.
Using a solution which sorts the original numbers and concatenates the numbers in order has a pitfall in that if you have something like { 9, 82, 99 }, the sorted array would be { 99, 82, 9 }. However, this would result in 99829, when the largest number would actually be 99982.
Since the brute force solution works, but may not be optimal in terms of performance, it might be good to check out ways to optimize the solution (after profiling the original solution, of course). For example, you could start with a simple ordering scheme by multiplying individual digits of a number by the place they would occupy.
{ 9, 98, 95 }
The above set will result in a 5 digit number. We'll apply a simple formula which multiplies the individual digit by its place (1 for 1's place, 2 for 10's place, etc.) and sums them like so:
9 -> 9 * 5
98 -> 9 * 5 + 8 * 4
95 -> 9 * 5 + 5 * 4
which results in
9 -> 45
98 -> 77
95 -> 65
Now, as humans, we know that the 9 should come first, not 98 or 95. One way to fix this would them be to favor single digit numbers if the first digits of the candidates are identical (ie, favor 9 or 98/95/etc.). Generalizing a bit, you might choose the candidate with fewer digits each time if the digits from the left are larger or equivalent (if the number of digits is equal, use the above formula). If we have { 9871, 986 }, 9871 would have a higher value, but we would look at 986 and see that it has fewer digits.
9 8 7 1
| | | |
9 8 6
8 matches, continue, 7 is larger, so ignore 986 (9871986 versus the smaller 9869871). If the set were { 9861, 987 } instead:
9 8 6 1
| | | |
9 8 7
8 matches, continue, 7 is larger, so choose 987 (9879861 versus the smaller 9861987).
So testing this using the following set:
{ 7, 61, 811, 99 }
The result will be an 8 digit number. Applying the placement formula gives:
7 -> 7 * 8 = 56
61 -> 6 * 8 + 1 * 7
811 -> 8 * 8 + 1 * 7 + 1 * 6 = 77
99 -> 9 * 8 + 9 + 7 = 135
So 99 looks like it will go first, but now let's apply the second part of the algorithm by selecting the numbers with fewer digits:
7
7 is not identical with 9, of course, so we are left with 99 as the first number.
9 9 _ _ _ _ _
Next iteration:
7 -> 7 * 6 = 42
61 -> 6 * 6 + 1 * 5 = 41
811 -> 8 * 6 + 1 * 5 + 1 * 4 = 57
811 has the highest value and both 61 an 7 do not have identical digits from left to right so we insert 811.
9 9 8 1 1 _ _ _
Next iteration:
7 -> 7 * 3 = 21
61 -> 6 * 3 + 1 * 2 = 20
7 has the higher value and nothing has fewer digits--insert:
9 9 8 1 1 7 _ _
Next iteration:
Only one number (61) is left, so we'll insert it
9 9 8 1 1 7 6 1 -> 99811761
and get the biggest number! Note that if 61 had been something like 81, it would have correctly ended up in 811's spot -> 99818117 instead of the incorrect 99811817.
Looking at the example {5,54,56}, the proper way to order these numbers is when comparing strings A and B, we should consider lexicographic ordering of A+B with B+A.
For example:
If we sort them this way, the resulting array is {56,5,54}.
Here's a Java implementation of this idea:
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));
}
}
This is my solution though it might not be efficient. The code is in 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()
As others have pointed out, a lexicographic sort and concatenation is close, but not quite correct. For example, for the numbers 5
, 54
, and 56
a lexicographic sort will produce {5, 54, 56} (in increasing order) or {56, 54, 5} (in decreasing order), but what we really want is {56, 5, 54}, since that produces the largest number possible.
So we want a comparator for two numbers that somehow puts the biggest digits first.
We can do that by comparing individual digits of the two numbers, but we have to be careful when we step off the end of one number if the other number still has remaining digits. There are lots of counters, arithmetic, and edge cases that we have to get right.
A cuter solution (also mentioned by @Sarp Centel) achieves the same result as (1) but with a lot less code. The idea is to compare the concatenation of two numbers with the reverse concatenation of those numbers. All of the cruft that we have to explicitly handle in (1) is handled implicitly.
For example, to compare 56
and 5
, we'd do a regular lexicographic comparison of 565
to 556
. Since 565
> 556
, we'll say that 56
is "bigger" than 5
, and should come first. Similarly, comparing 54
and 5
means we'll test 545
< 554
, which tells us that 5
is "bigger" than 54
.
Here's a simple example:
// 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] << ' ';
}
}
When run, this code displays:
9 96 95 56 556 5 55 554 54 3 2 1
Well , for one you can try this
You got the largest number