给定一组正整数,找到可以通过排列的任何排列形成的最大值。我想知道是否有更好的数据结构可以为问题提供更优雅的解决方案。
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;
}
}
答案 0 :(得分:3)
一般情况(将任意非负整数粘合在一起,不一定是数字),恕我直言,非常有趣,例如
[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();
答案 1 :(得分:1)
假设“正整数”是数字(考虑到排列的这个约束,对我来说没有其他意义),解决方案很简单:对整数数组进行排序,最大数字的第一个数字将是最大数字,第二个是第二大等,例如,给定一个数字数组1 5 7 3
,排序的数组是7 5 3 1
,所以最大的这个数字是7531.排序可以在{ {1}},or even in O(n)
。
编辑:如果数字不限制为单个数字,则从每个数字中提取所有数字,删除重复项并将它们添加到数组中,然后使用该数组执行排序等操作现在开始。
C ++演示:
O(n log n)
And it works, even with numbers with zeroes in them.
修改2:如果您不需要数字是唯一的,那么请使用向量而不是集合:
#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;
}
答案 2 :(得分:1)
假设您有一些1位数字,一些2位数,3位数,......,r位数。
按编号对您的数字分组为r列表,并对每个列表进行排序。在每一步中,您追加的数字将是其中一个列表的最大元素,因此如果数字集相对于r大,这将有所帮助。
,例如,[1,2,21,33,94,9,88] =&gt; [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。
唯一棘手的案例是他们是否平等。然后,比较该对可以进入的两个订单,并选择在两个中较大的一个中作为您的候选者的那个。我相信如果他们是平等的,那么选择是任意的,但却没有说服自己。