Fraction to Recurring Decimal

时间:2015-10-30 21:32:43

标签: java algorithm

Working on this problem, and also did a few reference to similar solutions. One thing I am confuse is, why we break the loop as long as there is one repetitive number? Is it possible the number repeat for 2-3 times and then changed to another different number? Thanks.

I mean this part specifically,

        if (map.containsKey(num)) {
            int index = map.get(num);
            res.insert(index, "(");
            res.append(")");
            break;
        }

The problem,

Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.

If the fractional part is repeating, enclose the repeating part in parentheses.

For example,

Given numerator = 1, denominator = 2, return "0.5". Given numerator = 2, denominator = 1, return "2". Given numerator = 2, denominator = 3, return "0.(6)".

public class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        if (numerator == 0) {
            return "0";
        }
        StringBuilder res = new StringBuilder();
        // "+" or "-"
        res.append(((numerator > 0) ^ (denominator > 0)) ? "-" : "");
        long num = Math.abs((long)numerator);
        long den = Math.abs((long)denominator);

        // integral part
        res.append(num / den);
        num %= den;
        if (num == 0) {
            return res.toString();
        }

        // fractional part
        res.append(".");
        HashMap<Long, Integer> map = new HashMap<Long, Integer>();
        map.put(num, res.length());
        while (num != 0) {
            num *= 10;
            res.append(num / den);
            num %= den;
            if (map.containsKey(num)) {
                int index = map.get(num);
                res.insert(index, "(");
                res.append(")");
                break;
            }
            else {
                map.put(num, res.length());
            }
        }
        return res.toString();
    }
}

thanks in advance, Lin

4 个答案:

答案 0 :(得分:3)

The code doesn't stop when it sees a digit repeated. It stops when it notes that it has reached a state which it was already in. If it reaches the same state again, it means that we are about to repeat a division that we have already done, which means that the dividend and remainder are going to be the same, and we are going to do the same series of steps we have already done.

When that happens, it means a repetition, and it stops and adds the parentheses.

For example, let's divide 123 by 999. This should give us the repeating decimal 0.123123123..., so the output should be 0.(123).

  • 123 / 999 is 0. The remainder is 123. We start with 0.
  • Multiply the remainder by 10. Now we have 1230 / 999. Dividend is 1, remainder is 231. Now we have 0.1
  • Multiply the remainder by 10. Now we have 2310 / 999. Dividend is 2, remainder is 312. Now we have 0.12
  • Multiply the remainder by 10. Now we have 3120 / 999. Dividend is 3, remainder is 123. Now we have 0.123
  • Multiply the remainder by 10. Now we have 1230 / 999... wait, we have already done that! That means that as we continue to divide, we'll get to that number again and again. Stop and put parentheses around the repeating part.

The map is there to tell us which numbers we have already divided, and at which index in the StringBuilder. When we find a number we have already divided, we use that index to know where to insert the parenthesis.

答案 1 :(得分:1)

Clearly it's possible to have a decimal number with two or more decimals recurring and then a different decimal. For example 449/1000 = 0.449

答案 2 :(得分:0)

如果我们使用我们在四年级学到的长分工艺,这个问题实际上很难解决。

假设您需要将92除以22.如何使用长除法进行此操作。你如何检测重复模式?

很简单,当您遇到以前遇到的提醒时,您知道您有一个重复的小数模式。您需要将提醒和结果的相应索引存储在字典中,并使用相同的方法检测/打印重复小数。在下面使用python代码。

def divide(numerator, denominator):
    sign, res, lead = '', '', ''
    if (numerator < 0) ^ (denominator < 0) and numerator != 0:
        sign = '-'
    numerator = abs(numerator)
    denominator = abs(denominator)
    remainders = defaultdict(list)

    if numerator < denominator:
        lead = '0'
    _x = str(numerator)
    r = 0
    i = 0
    j = 0
    while True:
        if i < len(_x):
            d = int(str(r)+_x[i])
            q = d // denominator
            if not (q == 0 and len(res) == 0):
                res += str(q)
            r = d - (q * denominator)
            i += 1
        elif i >= len(_x) and j <= 9223372036854775807:
            if r == 0:
                return sign+lead+res
            if j == 0:
                remainders[r] = [True, len(res)+1]
                res += '.'
            d = int(str(r) + '0')
            q = d // denominator
            res += str(q)
            r = d - (q * denominator)
            if remainders[r] and remainders[r][0]:
                res = res[0:remainders[r][1]] + '(' + res[remainders[r][1]:] + ')'
                return sign+lead+res
            remainders[r] = [True, len(res)]
            j += 1
        else:
            return sign+lead+res

答案 3 :(得分:0)

以下是我在Java中解决此问题的方法:

/**
 * Given two integers a and b, return the result as a String.
 * Display the repeating part of the fraction in parenthesis.
 *
 * Runs in O(b)
 *
 * @author Raed Shomali
 */
public class Divider {

    private static final String DOT = ".";
    private static final String ERROR = "ERROR";
    private static final String LEFT_PARENTHESIS = "(";
    private static final String RIGHT_PARENTHESIS = ")";

    public static String divide(final int a, final int b){
        if (b == 0) {
            return ERROR;
        }

        int value = a / b;
        int remainder = a % b;
        return String.valueOf(value) + DOT + divider(remainder, b);
    }

    private static String divider(final int a, final int b) {
        final Map<Integer, Integer> remainderIndexMap = new HashMap<>();
        final List<Integer> values = new ArrayList<>();

        int value;
        int remainder = a;
        while (!remainderIndexMap.containsKey(remainder)) {
            remainderIndexMap.put(remainder, values.size());

            remainder *= 10;
            value = remainder / b;
            remainder = remainder % b;
            values.add(value);
        }

        final int index = remainderIndexMap.get(remainder);
        final StringBuilder result = new StringBuilder();
        for (int i = 0; i < index; i++) {
            result.append(values.get(i));
        }
        result.append(LEFT_PARENTHESIS);
        for (int i = index; i < values.size(); i++) {
            result.append(values.get(i));
        }
        result.append(RIGHT_PARENTHESIS);
        return result.toString();
    }
}

基本上,这个想法很简单。使用相同的长除法技术,您知道何时在已经看到相同的remainder值时停止。

以下是一些显示几种不同场景的测试用例:

divide(0, 0)     // "ERROR"
divide(1, 2)     // "0.5(0)"
divide(0, 3)     // "0.(0)"
divide(10, 3)    // "3.(3)"
divide(22, 7)    // "3.(142857)"
divide(100, 145) // "0.(6896551724137931034482758620)"

如果您对使用Go编写的解决方案感兴趣,可以在此处找到https://github.com/shomali11/util