简体   繁体   English

循环小数的分数

[英]Fraction to Recurring Decimal

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?是否有可能该数字重复 2-3 次,然后更改为另一个不同的数字? 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".给定分子 = 1,分母 = 2,返回“0.5”。 Given numerator = 2, denominator = 1, return "2".给定分子 = 2,分母 = 1,返回“2”。 Given numerator = 2, denominator = 3, return "0.(6)".给定分子 = 2,分母 = 3,返回“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提前致谢,林

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。这应该给我们重复的十进制 0.123123123...,所以输出应该是0.(123)

  • 123 / 999 is 0. The remainder is 123. We start with 0. 123 / 999 是 0。余数是 123。我们从0.开始0.
  • Multiply the remainder by 10. Now we have 1230 / 999. Dividend is 1, remainder is 231. Now we have 0.1将余数乘以 10。现在我们有 1230 / 999。股息是 1,余数是 231。现在我们有0.1
  • Multiply the remainder by 10. Now we have 2310 / 999. Dividend is 2, remainder is 312. Now we have 0.12将余数乘以 10。现在我们有 2310 / 999。股息是 2,余数是 312。现在我们有0.12
  • Multiply the remainder by 10. Now we have 3120 / 999. Dividend is 3, remainder is 123. Now we have 0.123将余数乘以 10。现在我们有 3120 / 999。股息是 3,余数是 123。现在我们有0.123
  • Multiply the remainder by 10. Now we have 1230 / 999... wait, we have already done that!将余数乘以 10。现在我们有 1230 / 999...等等,我们已经做到了! 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 .地图告诉我们我们已经划分了哪些数字,以及StringBuilder哪个索引。 When we find a number we have already divided, we use that index to know where to insert the parenthesis.当我们找到一个我们已经除过的数字时,我们使用该索引来知道在哪里插入括号。

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例如 449/1000 = 0.449

This problem is actually very simple to solve if we use the long division technique that we learnt in 4th grade.这个问题其实用四年级学过的长除法就很容易解决了。

Suppose you need to divide 92 by 22. How do you do it using the long division method.假设你需要将 92 除以 22。你如何使用长除法来做。 How do you detect a repeating pattern?如何检测重复模式?

Simple, you know you have a repeating pattern of decimals when you encounter a previously encountered reminder .很简单,当您遇到以前遇到的提醒时,您知道您有一个重复的小数模式。 You'll need to store the reminders and the corresponding index of the result in a dictionary and using the same you could detect/print repeating decimals.您需要将提醒和结果的相应索引存储在字典中,并使用相同的内容可以检测/打印重复的小数。 Working python code below.下面的工作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

Here is my solution in Java to this problem:这是我在 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();
    }
}

Basically, the idea is simple.基本上,这个想法很简单。 Using the same long division technique, you know when to stop when you have already seen the same remainder value.使用相同的长除法技术,当您已经看到相同的remainder数值时,您知道何时停止。

Here are some test cases to show a few different scenarios:以下是一些测试用例,用于展示几种不同的场景:

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)"

If you are interested in a solution written in Go , you can find it here https://github.com/shomali11/util如果你对用Go编写的解决方案感兴趣,你可以在这里找到它https://github.com/shomali11/util

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM