简体   繁体   中英

Digit root of some positive integer is defined as the sum of all of its digits

I am trying to solve this challenge on an online challenge site and I am a bit stuck. Here is a bit more about the problem:

You are given an array of integers. Sort it in such a way that if a comes before b then the digit root of a is less than or equal to the digit root of b. If two numbers have the same digit root, the smaller one (in the regular sense) should come first. For example 4 and 13 have the same digit root, however 4 < 13 thus 4 comes before 13 in any digitRoot sorting where both are present.

Here is my output:

Input: a: [13, 20, 7, 4]
Output: [20, 13, 4, 7]
Expected Output: [20, 4, 13, 7]

Here is my code:

int digitRoot(int b) {
    int c, sum = 0;
    while(b>0) {
        c=b%10;
        sum=sum+c;
        b=b/10;
    }
    return sum;
}

int[] digitRootSort(int[] a) {
    HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>();
    int[] a1 = new int[a.length];
    for (int i=0;i<a.length;i++) {
        a1[i]=digitRoot(a[i]);
        if (map.containsKey(a1[i])) {
            ArrayList<Integer> temp = map.get(a1[i]);
            temp.add(a[i]);
            map.put(a1[i], temp);
        }
        else { 
            ArrayList<Integer> list = new ArrayList<Integer>();
            list.add(a[i]);
            map.put(a1[i], list);
        }
    }
    Arrays.sort(a1);
    for (int i=0;i<a.length;i++) {
        ArrayList<Integer> temp = map.get(a1[i]);
        for(int j=0;j<temp.size();j++) {
            a[i]=temp.get(j);
            if (j<temp.size()-1)
                i++;
        }
    }
    return a;
}

But if I change map.put(a1[i], temp); to map.put(a1[i], Collections.sort(temp));, I get this error: file.java on line 24:

 error: 'void' type not allowed here
                map.put(a1[i], Collections.sort(list));

You seem to be trying to insert the sorted value of the collection. Collections.sort(List) , for better or for worse, sorts that list in-place and returns nothing. Sort the list first, then insert it into the map.

Just include this one Collections.sort(temp); at your last for loop this is necessary because multiple numbers can have the same digitRoot and should be put on the list sorted.

for (int i=0;i<a.length;i++) {
        ArrayList<Integer> temp = map.get(a1[i]);
        Collections.sort(temp);
        for(int j=0;j<temp.size();j++) {
            a[i]=temp.get(j);
            if (j<temp.size()-1)
                i++;
        }
    }


Input: a: [13, 20, 7, 4]
Output: [20, 4, 13, 7]

Edit: about the error

because in put(a1[i], Collections.sort(list)) the put method is expecting put(int, List) , but you are giving it put(int, void) , because the return type of Collections.sort() is void , you just have to first sort the list and pass afterwards

Seems you're over-complicating things. Write a Comparator implementing the sorting rules, and simply sort the values.

Since you cannot sort an int[] using a Comparator , you first have to box the values, but otherwise it's very easy, especially using Java 8+ streams.

static int[] digitRootSort(int... values) {
    return IntStream.of(values).boxed()
                    .sorted(new DigitRootComparator())
                    .mapToInt(Integer::intValue).toArray();
}

static final class DigitRootComparator implements Comparator<Integer> {
    @Override
    public int compare(Integer a, Integer b) {
        int cmp = Integer.compare(digitRoot(a), digitRoot(b));
        return (cmp != 0 ? cmp : Integer.compare(a, b));
    }
    private static int digitRoot(int value) {
        int sum = 0;
        for (int remain = value; remain > 0; remain /= 10)
            sum += remain % 10;
        return sum;
    }
}

Test

System.out.println(Arrays.toString(digitRootSort(13, 20, 7, 4)));

Output

[20, 4, 13, 7]

You do not need to sort the array while putting in the map. Instead, you can sort it on retrieval in the last loop:

    Arrays.sort(a1);
    for (int i=0;i<a.length;i++) {
        ArrayList<Integer> temp = map.get(a1[i]);
        Collections.sort(temp);
        for(int j=0;j<temp.size();j++) {
            a[i]=temp.get(j);
            if (j<temp.size()-1)
                i++;
        }
    }

If you need to sort at the time of putting in the map, you should use a SortedSet as that will automatically keep the elements sorted:

int[] digitRootSort(int[] a) {
    HashMap<Integer, TreeSet<Integer>> map = new HashMap<Integer, TreeSet<Integer>>();
    int[] a1 = new int[a.length];
    for (int i = 0; i < a.length; i++) {
        a1[i] = digitRoot(a[i]);
        if (map.containsKey(a1[i])) {
            TreeSet<Integer> set = map.get(a1[i]);
            set.add(a[i]);
            map.put(a1[i], set);
        } else {
            TreeSet<Integer> set = new TreeSet<Integer>();
            set.add(a[i]);
            map.put(a1[i], set);
        }
    }
    Arrays.sort(a1);
    for (int i = 0; i < a.length;) {
        TreeSet<Integer> set = map.get(a1[i]);
        for (int j : set) {
            a[i] = j;
            i++;
        }
    }
    return a;
}

However, there is even a simpler way to do with sorted set, by using an appropriate comparator:

int[] digitRootSort(int[] a) {
    SortedSet<Integer> set = new TreeSet<Integer>(new Comparator<Integer>() {

        @Override
        public int compare(Integer a, Integer b) {
            int result = Integer.compare(digitRoot(a), digitRoot(b));
            result = result == 0 ? Integer.compare(a, b) : result;
            return result;
        }
    });

    for (int i : a) {
        set.add(i);
    }

    int i = 0;
    for (int j : set) {
        a[i++] = j;
    }

    return a;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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