簡體   English   中英

如何找到小於N的最大數M,其中Java中不允許存在某些特定數字

[英]how to find maximum number M less than N in which some specific digit is not allowed to exist in Java

最近,我遇到了一個采訪編程問題,關於如何找到小於N的最大數M,並且M中不允許存在某些特定數字。

例如,N = 123,digit = 2,則將輸出:119

我的想法是先將N轉換為字符串,然后從左到右找到數字的第一個位置,以使該數字減少1。然后,將N中的所有其余數字設置為9,以使該數字最大化。 有人可以指出我忽略的一些極端情況嗎? 在Java中是否有此問題的良好實現供參考?

...首先將N轉換為字符串,然后從左到右找到數字的第一個位置,以使該數字減少1。

這似乎很困難。 您將如何“找到使數字下降的位置”?

為什么不采用更強力的方法:將數字保留為數字,一一減少,轉換為字符串以查找數字是否存在,例如:

public int getMaxN(int N, char digit) {
    for (int i = N; i > 0; --i) {
        if (Integer.toString(i).indexOf(digit) == -1) {
            return i;
        }
    }
    throw new NoSuchElementException();
}

@Test
public void testGetMaxN() {
    assertEquals(119, getMaxN(123, '2'));
    assertEquals(122, getMaxN(123, '3'));
    assertEquals(99, getMaxN(123, '1'));
}

@Test(expected = NoSuchElementException.class)
public void testNoSuchElement() {
    getMaxN(0, '0');
}

可能存在更智能和有效的方法。

嘗試3。仍然是O(n),但是由於特殊的0情況需要級聯備份:

static int banDigit(int number, int digit) {
    int length = (Integer.toString(number)).length();
    int result = 0;
    boolean foundDigit = false;
    for (int i = length - 1; i >= 0; i--) {
        if (!foundDigit) {
            int currentDigit = (int) number / ((int) Math.pow(10, i));
            number = number % (int) Math.pow(10, i);
            if (currentDigit == digit) {
                //if nonzero digit banned, we can just decrement and purge 9 or 8 to right
                if (digit > 0) {
                    currentDigit--;
                } else {
                    // we have to subtract one from the previous 
                    result = result - (int) Math.pow(10, i);
                    //then we have to check if doing that caused a bunch of ones prior
                    for (int j = i + 1; j < length; j++) {
                        if ((int) (result % (int) Math.pow(10, j + 1)) / (int) Math.pow(10, j) == 0) {
                            result = result - (int) Math.pow(10, j);
                        }
                    }
                }
                foundDigit = true;
            }
            result += currentDigit * Math.pow(10, i);
        } else if (digit == 9) {
            result += 8 * Math.pow(10, i);
        } else {
            result += 9 * Math.pow(10, i);
        }
    }
    return result;
}

我使用的技巧是找到正確的數字以從原始數字中減去,並最大化剩余的數字。 通常,這只是一個數字,第一個不良數字位置為1,但是如果將被禁止的數字設為0,則比較棘手,因為當減法進行下去時,它可以產生更多的0。 當一串數字(如1110)在0之前位於1時,就會發生這種情況。 我的程序在O(n)時間解決方案中跟蹤這些值,其中n是位數。

import java.math.BigInteger;
import java.util.Arrays;

public class RemoveDigits {

  public static BigInteger removeDigits(BigInteger number, int banned) {
    char[] digits = number.toString().toCharArray(); // digits of the number
    char[] subtractChars = null; // array used to initialize BigInteger to subtract from the bad digit
    char maxDigit = banned == 9 ? '8' : '9'; // digit to fill rest of the number with
    int badCarryIndex = -1; // if banned == 0 keep track of the carry possibility
    int badDigitIndex = -1;
    for (int i = 0; i < digits.length; i++) {
      if (banned == 0 && digits[i] == '1') { // keep track of first character affected by carry
        if (badCarryIndex < 0) {
          badCarryIndex = i;
        }
      } else if (Character.digit(digits[i], 10) == banned) {
        badDigitIndex = i;
        if (badCarryIndex != 0) { // calculate the real first character affected by carry
          badCarryIndex--;
        }
        subtractChars = badCarryIndex < 0 ? new char[digits.length - badDigitIndex] : new char[digits.length - badCarryIndex - 1];
        subtractChars[0] = '1';
        break;
      } else { // reset if found a good character
        badCarryIndex = -1;
      }
    }
    if (badDigitIndex >= 0) {
      // fill the rest of the digits with maxDigit
      Arrays.fill(digits, badDigitIndex + 1, digits.length, maxDigit);
      // build subtractChars
      if (badCarryIndex >= 0) {
        // banned == 0, have to worry about carry producing 0's
        Arrays.fill(subtractChars, 1, badDigitIndex - badCarryIndex, '1');
        Arrays.fill(subtractChars, badDigitIndex - badCarryIndex, subtractChars.length, '0');
      } else {
        Arrays.fill(subtractChars, 1, subtractChars.length, '0');
      }
      BigInteger maxedNumber = new BigInteger(new String(digits));
      BigInteger subtractNumber = new BigInteger(new String(subtractChars));
      return maxedNumber.subtract(subtractNumber);
    }
    return number; // no bad digits in original number
  }

  public static void main(String[] args) {
    System.out.println(removeDigits(new BigInteger("20"), 0));
    System.out.println(removeDigits(new BigInteger("210"), 0));
    System.out.println(removeDigits(new BigInteger("123"), 0));
    System.out.println(removeDigits(new BigInteger("123"), 2));
    System.out.println(removeDigits(new BigInteger("1000"), 0));
    System.out.println(removeDigits(new BigInteger("1000"), 1));
    System.out.println(removeDigits(new BigInteger("1111020"), 0));
    System.out.println(removeDigits(new BigInteger("2011020"), 0));
    System.out.println(removeDigits(new BigInteger("80000009"), 9));
    System.out.println(removeDigits(new BigInteger("80937921"), 9));
  }
}

它打印:

19
199
123
119
999
999
999999
999999
80000008
80888888

編輯:修復了JoJo指出的拐角案例。

我認為可以,請告訴我是否有任何處理不當的案件。

public static void main(String[] args) {
    int N     = 100211020;
    int digit = 0;

    int m;
    for (m = 9 ; m > 0 && m == digit; m--);

    String sres;
    String s   = N + "";
    int length = s.length();
    int i      = s.indexOf(digit + "");

    if (i < 0)
        sres = s;
    else {
        StringBuilder sb = new StringBuilder();
        if (digit != 0) {
            for (int j=0 ; j<i ; j++) sb.append(s.charAt(j));
            sb.append(digit - 1);
            for (int j=i + 1 ; j<length ; j++) sb.append(m);
        } else {
            if (s.charAt(0) != '1')
                sb.append(mod10(s.charAt(0) - '0' - 1));
            for (int j=1 ; j<length ; j++) sb.append(9);            
        }
        sres = sb.toString();
    }
    System.out.println(sres);
}

public static int mod10(int n) {
    int res = n % 10;
    return res < 0 ? res + 10 : res;
}

編輯:

我最終決定使用字符串來處理digit = 0的情況,這與我的第一種方法相當復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM