Task: Fraction reduction
C#: using System;

namespace FractionReduction {
    class Program {
        static int IndexOf(int n, int[] s) {
            for (int i = 0; i < s.Length; i++) {
                if (s[i] == n) {
                    return i;
                }
            }
            return -1;
        }

        static bool GetDigits(int n, int le, int[] digits) {
            while (n > 0) {
                var r = n % 10;
                if (r == 0 || IndexOf(r, digits) >= 0) {
                    return false;
                }
                le--;
                digits[le] = r;
                n /= 10;
            }
            return true;
        }

        static int RemoveDigit(int[] digits, int le, int idx) {
            int[] pows = { 1, 10, 100, 1000, 10000 };

            var sum = 0;
            var pow = pows[le - 2];
            for (int i = 0; i < le; i++) {
                if (i == idx) continue;
                sum += digits[i] * pow;
                pow /= 10;

            }
            return sum;
        }

        static void Main() {
            var lims = new int[,] { { 12, 97 }, { 123, 986 }, { 1234, 9875 }, { 12345, 98764 } };
            var count = new int[5];
            var omitted = new int[5, 10];
            var upperBound = lims.GetLength(0);
            for (int i = 0; i < upperBound; i++) {
                var nDigits = new int[i + 2];
                var dDigits = new int[i + 2];
                var blank = new int[i + 2];
                for (int n = lims[i, 0]; n <= lims[i, 1]; n++) {
                    blank.CopyTo(nDigits, 0);
                    var nOk = GetDigits(n, i + 2, nDigits);
                    if (!nOk) {
                        continue;
                    }
                    for (int d = n + 1; d <= lims[i, 1] + 1; d++) {
                        blank.CopyTo(dDigits, 0);
                        var dOk = GetDigits(d, i + 2, dDigits);
                        if (!dOk) {
                            continue;
                        }
                        for (int nix = 0; nix < nDigits.Length; nix++) {
                            var digit = nDigits[nix];
                            var dix = IndexOf(digit, dDigits);
                            if (dix >= 0) {
                                var rn = RemoveDigit(nDigits, i + 2, nix);
                                var rd = RemoveDigit(dDigits, i + 2, dix);
                                if ((double)n / d == (double)rn / rd) {
                                    count[i]++;
                                    omitted[i, digit]++;
                                    if (count[i] <= 12) {
                                        Console.WriteLine("{0}/{1} = {2}/{3} by omitting {4}'s", n, d, rn, rd, digit);
                                    }
                                }
                            }
                        }
                    }
                }
                Console.WriteLine();
            }

            for (int i = 2; i <= 5; i++) {
                Console.WriteLine("There are {0} {1}-digit fractions of which:", count[i - 2], i);
                for (int j = 1; j <= 9; j++) {
                    if (omitted[i - 2, j] == 0) {
                        continue;
                    }
                    Console.WriteLine("{0,6} have {1}'s omitted", omitted[i - 2, j], j);
                }
                Console.WriteLine();
            }
        }
    }
}

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;
    }

}