-4

I want to permute the digits of an int in a way that the result is the biggest possible permutation. This is easily done like this:

//how to deal with really large ints e.g.int32.MaxValue goes here 
// in this case the algorithm would need to round down to the largest possible value 
// but still needs to be less than int32.MaxValue 
//This code will just handle normal values <int32.MaxValue 
public static int Max(int number)
{
    var numberAsCharArray = number.ToString().OrderByDescending(c => c).ToArray();
    var largestNumberAsString = new string(numberAsCharArray);
    return Int32.Parse(largestNumberAsString);
}

However, when the input has the same number of digits as Int32.MaxValue and contains at least one high digit, this digit will go to the first position making the result > Int32.MaxValue and leading to an exception when converting to int.

How could I limit the result to be <= Int32.MaxValue but within this limit still be the greatest possible permutation?

N.B. Negative numbers, e.g. -1234567890 are allowed as well as positive ones; in case of negative input, - sign should be dropped: -1234567890 should produce 2147398650 output

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • What are you trying to do? – Prajwal Jan 09 '17 at 08:02
  • 10
    Could you, please, add some examples. What is the solution in case of `345` and why? When I read as it put "largest possible value of an int that is less than the number itself" I get `344` as an answer for `345` (`answer = numberInput - 1`). – Dmitry Bychenko Jan 09 '17 at 08:03
  • 1
    Possible duplicate of [Listing all permutations of a string/integer](http://stackoverflow.com/questions/756055/listing-all-permutations-of-a-string-integer) – Daniel B Jan 09 '17 at 08:08
  • 1
    Maybe, the number is 587 and you want to find the largest number from 5, 8, and 7 only. And this number is less than 587. The result is 578. Is it right? – GSP Jan 09 '17 at 08:09
  • Ok, so the context I am using it is in this...I have an algorithm for finding the largest value of an int based on the input. So 345 would give me 543. But I need to cater for situations if a user enters a max value not supported by the int type e.g. any value > int32.MaxValue. My algorithm crashes out here because if the user enters 2147483647 and I get the max possible value this will not work because its not supported by int type. What I want to happen in this situation is that it still finds the max value but it needs to be less than 2147483647 itself. Does that make sense? – user7393401 Jan 09 '17 at 08:12
  • @user7393401: try `long`, `BigInteger` instead of `int` if `int32.MaxValue` is the problem – Dmitry Bychenko Jan 09 '17 at 08:13
  • No it is a requirement to stick with int – user7393401 Jan 09 '17 at 08:20
  • You can use int FindBiggestNumber(int input); But in this method you can assign **input** to a long variable. Then you can process it as a long integer. And you can compare with int32.MaxValue – GSP Jan 09 '17 at 08:22
  • 1
    You're not actually doing math on it right? Use a string. So your just taking the integers in the number and rearranging them in descending order. – Rabid Penguin Jan 09 '17 at 08:24
  • Nevermind, after rereading your question I'm not sure what you mean, unless you mean to rearrange them in ascending order. In which case the answer to 345 is 345. Your question has melted my brain. – Rabid Penguin Jan 09 '17 at 08:27
  • You said that "My algorithm crashes out here because if the user enters 2147483647". You should use try{} catch{}. If you got an exception, you just return to generate another number which less than previous number. – GSP Jan 09 '17 at 08:33
  • public int Max(int number) { //how to deal with really large ints e.g. int32.MaxValue goes here // in this case the algorithm would need to round down to the largest possible value // but still needs to be less than int32.MaxValue //This code will just handle normal values c).ToArray(); var largestNumberAsString = new string(numberAsCharArray); return Int32.Parse(str); } Does it make sense what I am trying to do now? – user7393401 Jan 09 '17 at 08:53
  • Does the result have to be strictly lower than the input or would equal be fine, too? – wkl Jan 09 '17 at 09:42
  • I just wanted to delete my question because I felt it was stupid. But now you answered equal would be fine which makes me wonder: Wouldn't the result be the input then? – wkl Jan 09 '17 at 09:44
  • Once you find the largest value(from the input) this value needs to be either <= int32.MaxValue. Does that make sense? – user7393401 Jan 09 '17 at 09:52
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/132681/discussion-on-question-by-user7393401-finding-the-largest-possible-number-in-per). – Bhargav Rao Jan 09 '17 at 10:01
  • It would bypass the problem of the int not being able to handle massive numbers? – user7393401 Jan 09 '17 at 13:04
  • what do you mean wkl? – user7393401 Jan 09 '17 at 13:08
  • in this scenario wouldnt the input of int.maxValue be the actual return value itself – user7393401 Jan 09 '17 at 13:10
  • @Henk can you set this question so it is not on hold anymore please – user7393401 Jan 09 '17 at 13:33
  • 1
    The test case for `1234567890` is `2147398650`, right? (`int.MaxValue == 2147483647` for reference) – Dmitry Bychenko Jan 09 '17 at 13:46

2 Answers2

2

For small numbers (less or equal to 1000000000) you can do the business as usual; for numbers greater than one billion you can try the follow approach:

  1. Try follow int.MaxValue pattern (2147483647) as long as it's possible
  2. When it's not possible, put the maximum number you can do and continue doing the business as usual for the remaining digits.

For instance, given 1234567890

  1234567890 <- initial value
  2147483647 <- int.MaxValue pattern
  2147398650 <- solution
      ^
      |
      Here we can't put another 4, we put maximum available - 3

  Remaining digits [56890] we order by descending - "98650" - business as usual

Implementation

private static int Biggest(int value) {
  // Special MinValue case; 
  // we can't do Math.Abs() because of integer overflow
  if (value == int.MinValue)
    return 2147483486;

  string st = value.ToString().Trim('-');

  if (value <= 1000000000 && value >= -1000000000)
    return int.Parse(string.Concat(st.OrderByDescending(c => c)));

  string max = int.MaxValue.ToString();

  List<int> digits = st.Select(c => c - '0').ToList();

  StringBuilder sb = new StringBuilder(9);

  bool exact = true;

  while (digits.Any()) {
    for (int i = 0; i < max.Length; ++i) {
      int digitToFind = max[i] - '0';

      int digitActual;

      digitActual = digits
        .Where(d => !exact || d <= digitToFind)
        .OrderByDescending(d => d)
        .First();

      if (exact)
        exact = digitActual == digitToFind;

      sb.Append(digitActual);

      digits.Remove(digitActual);
    }
  }

  return int.Parse(sb.ToString());
}

Test:

// 2147398650 (for reference: int.MaxValue == 2147483647)
Console.WriteLine(Biggest(1234567890));
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
0

I suggest this:

int number = 587;
int maximum = Int32.MaxValue;
var result = "";
if(number == Int32.MinValue)
{
    result = "2147483486";
}
else
{ 
    // create list of available digits removing - sign from the string
    var inputDigits = number.ToString().Replace("-", String.Empty).Select(c => Int32.Parse(new string(c, 1))).ToList();
    var limitDigits = maximum.ToString().Select(c => Int32.Parse(new string(c, 1))).ToList();
    var orderedDigits = inputDigits.OrderByDescending(c => c).ToList();
    int position = 0;
    // we only have to compare to the maximum if we have at least the same amount of digits in the input.
    bool compareValues = limitDigits.Count <= inputDigits.Count;
    // while we have not used all of the digits
    while (orderedDigits.Count > 0)
    {
        // loop over the remaining digits from high to low values
        for (int i = 0; i < orderedDigits.Count; i++)
        {
            // if it is above the digit in the maximum at the corresponding place we may only use it if input is shorter than maximum or if we have already used a lower value in a previous digit.
            if (orderedDigits[i] > limitDigits[position])
            {
                if (compareValues)
                {
                    continue;
                }
            }
            else if (orderedDigits[i] < limitDigits[position])
            {
                // remember that we have already used a lower value
                compareValues = false;
            }
            result += (orderedDigits[i].ToString());
            orderedDigits.RemoveAt(i);
            break;
        }
        position++;
    }
}
var intResult = Int32.Parse(result);

EDIT:

inserted .Replace("-", String.Empty) when defining inputDigits to support negative numbers

wkl
  • 1,896
  • 2
  • 15
  • 26
  • How would you deal with -2,147,483,648? In this case it should just treat it as a positive number (ignoring the sign) – user7393401 Jan 09 '17 at 14:01
  • Insert `number=Math.Abs(number);` at the beginning. And update your question to mention negative numbers. – wkl Jan 09 '17 at 14:04
  • Still an exception because removing the minus still creates an in > int.MaxValue? – user7393401 Jan 09 '17 at 14:06
  • @wkl: `Math.Abs(int.MinValue)` will cause *integer overflow* since `int.MinValue == -int.MaxValue - 1` @user7393401: please add *negative* numbers into the question (that we should remove the `-` sign) – Dmitry Bychenko Jan 09 '17 at 14:08
  • @DmitryBychenko Thank you, I missed that one. – wkl Jan 09 '17 at 14:10
  • I dont understand what you mean wkl – user7393401 Jan 09 '17 at 14:18
  • @wkl: `int.MinValue` is a *special case*; please, try `int number = int.MinValue;` and you'll fail with exception at `if (orderedDigits[i] > limitDigits[position]) {` line. However, the solution in this special case is `2147483486` – Dmitry Bychenko Jan 09 '17 at 14:23
  • @DmitryBychenko You are right, my algorithm cannot handle this number. You have to check for it in the beginning. I will edit it correspondingly. – wkl Jan 09 '17 at 14:40