Task: Fraction reduction




Go: package main

import (
    "fmt"
    "time"
)

func indexOf(n int, s []int) int {
    for i, j := range s {
        if n == j {
            return i
        }
    }
    return -1
}

func getDigits(n, le int, digits []int) bool {
    for n > 0 {
        r := n % 10
        if r == 0 || indexOf(r, digits) >= 0 {
            return false
        }
        le--
        digits[le] = r
        n /= 10
    }
    return true
}

var pows = [5]int{1, 10, 100, 1000, 10000}

func removeDigit(digits []int, le, idx int) int {
    sum := 0
    pow := pows[le-2]
    for i := 0; i < le; i++ {
        if i == idx {
            continue
        }
        sum += digits[i] * pow
        pow /= 10
    }
    return sum
}

func main() {
    start := time.Now()
    lims := [5][2]int{
        {12, 97},
        {123, 986},
        {1234, 9875},
        {12345, 98764},
        {123456, 987653},
    }
    var count [5]int
    var omitted [5][10]int
    for i, lim := range lims {
        nDigits := make([]int, i+2)
        dDigits := make([]int, i+2)
        blank := make([]int, i+2)
        for n := lim[0]; n <= lim[1]; n++ {
            copy(nDigits, blank)
            nOk := getDigits(n, i+2, nDigits)
            if !nOk {
                continue
            }
            for d := n + 1; d <= lim[1]+1; d++ {
                copy(dDigits, blank)
                dOk := getDigits(d, i+2, dDigits)
                if !dOk {
                    continue
                }
                for nix, digit := range nDigits {
                    if dix := indexOf(digit, dDigits); dix >= 0 {
                        rn := removeDigit(nDigits, i+2, nix)
                        rd := removeDigit(dDigits, i+2, dix)
                        if float64(n)/float64(d) == float64(rn)/float64(rd) {
                            count[i]++
                            omitted[i][digit]++
                            if count[i] <= 12 {
                                fmt.Printf("%d/%d = %d/%d by omitting %d's\n", n, d, rn, rd, digit)
                            }
                        }
                    }
                }
            }
        }
        fmt.Println()
    }

    for i := 2; i <= 6; i++ {
        fmt.Printf("There are %d %d-digit fractions of which:\n", count[i-2], i)
        for j := 1; j <= 9; j++ {
            if omitted[i-2][j] == 0 {
                continue
            }
            fmt.Printf("%6d have %d's omitted\n", omitted[i-2][j], j)
        }
        fmt.Println()
    }
    fmt.Printf("Took %s\n", time.Since(start))
}


Java: import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FractionReduction {

    public static void main(String[] args) {
        for ( int size = 2 ; size <= 5 ; size++ ) {
            reduce(size);
        }
    }
    
    private static void reduce(int numDigits) {
        System.out.printf("Fractions with digits of length %d where cancellation is valid.  Examples:%n", numDigits);
        
        
        int min = (int) Math.pow(10, numDigits-1);
        int max = (int) Math.pow(10, numDigits) - 1;
        List<Integer> values = new ArrayList<>();
        for ( int number = min ; number <= max ; number++ ) {
            if ( isValid(number) ) {
                values.add(number);
            }
        }
        
        Map<Integer,Integer> cancelCount = new HashMap<>(); 
        int size = values.size();
        int solutions = 0;
        for ( int nIndex = 0 ; nIndex < size - 1 ; nIndex++ ) {
            int numerator = values.get(nIndex);
            
            for ( int dIndex = nIndex + 1 ; dIndex < size ; dIndex++ ) {
                int denominator = values.get(dIndex);
                for ( int commonDigit : digitsInCommon(numerator, denominator) ) {
                    int numRemoved = removeDigit(numerator, commonDigit);
                    int denRemoved = removeDigit(denominator, commonDigit);
                    if ( numerator * denRemoved == denominator * numRemoved ) {
                        solutions++;
                        cancelCount.merge(commonDigit, 1, (v1, v2) -> v1 + v2);
                        if ( solutions <= 12 ) {
                            System.out.printf("    When %d is removed, %d/%d = %d/%d%n", commonDigit, numerator, denominator, numRemoved, denRemoved);
                        }
                    }
                }
            }
        }
        System.out.printf("Number of fractions where cancellation is valid = %d.%n", solutions);
        List<Integer> sorted = new ArrayList<>(cancelCount.keySet());
        Collections.sort(sorted);
        for ( int removed : sorted ) {
            System.out.printf("    The digit %d was removed %d times.%n", removed, cancelCount.get(removed));
        }
        System.out.println();
    }
    
    private static int[] powers = new int[] {1, 10, 100, 1000, 10000, 100000};
    
    
    private static int removeDigit(int n, int removed) {
        int m = 0;
        int pow = 0;
        while ( n > 0 ) {
            int r = n % 10;
            if ( r != removed ) {
                m = m + r*powers[pow];
                pow++;
            }
            n /= 10;
        }
        return m;
    }
        
    
    private static List<Integer> digitsInCommon(int n1, int n2) {
        int[] count = new int[10];
        List<Integer> common = new ArrayList<>();
        while ( n1 > 0 ) {
            int r = n1 % 10;
            count[r] += 1;
            n1 /= 10;
        }
        while ( n2 > 0 ) {
            int r = n2 % 10;
            if ( count[r] > 0 ) {
                common.add(r);
            }
            n2 /= 10;
        }
        return common;
    }
    
    
    private static boolean isValid(int num) {
        int[] count = new int[10];
        while ( num > 0 ) {
            int r = num % 10;
            if ( r == 0 || count[r] == 1 ) {
                return false;
            }
            count[r] = 1;
            num /= 10;
        }
        return true;
    }

}