-1

I'm trying to solve the following question:

Given an array of numbers with only 3 unique numbers (1, 2, 3), sort the list in O(n) time.

Example 1:

Input: [3, 3, 2, 1, 3, 2, 1]

Output: [1, 1, 2, 2, 3, 3, 3]

Challenge: Try sorting the list using constant space

The first part where I can use extra space is easy, basically what I did is find the min,max and the middle value store them as keys in a hashmap and their frequencies as the hashmap values, and then fill the new created array with the correct values:

import java.util.Map;
import java.util.HashMap;
class Testing{

    public static void sortArr(int[] arr){
        int[] newArr=new int[arr.length];
        Map<Integer,Integer> hm=new HashMap<Integer,Integer>(3);
        int mini=minArr(arr);
        int maxi=maxArr(arr);
        int midNum=Integer.MAX_VALUE;
        
        for(int num : arr){
            if(hm.containsKey(num)){
                hm.put(num,hm.get(num)+1);
            }else{hm.put(num,1);}
        }

        for(int num : hm.keySet()){
            if(num!=mini && num!=maxi){
                midNum=num;
                break;
            }
        }

        for(int i=0;i<arr.length;++i){
            if(i<hm.get(mini)){
                newArr[i]=mini;
            }else if(i>(arr.length-hm.get(maxi))){
                newArr[i]=maxi;
            }else{
                newArr[i]=midNum;
            }
        }

        for(int num : newArr){
            System.out.println(num);
        }
    }

    public static int minArr(int[] arr){
        int mini=Integer.MAX_VALUE;
        for(int num : arr){
            if(num<mini){
                mini=num;
            }
        }
        return mini;
    }

    public static int maxArr(int[] arr){
        int maxi=Integer.MIN_VALUE;
        for(int num : arr){
            if(num>maxi){
                maxi=num;
            }
        }
        return maxi;
    }


    public static void main(String args[]){
        int[] arr={-4,-4,9,9,-4,3,9,3,3,3,3,9,9,-4,9,3};
        sortArr(arr);
    }
}

What I'm interested is the Challenge part, which I'm unable to solve, any help is appreciated, thanks.

Community
  • 1
  • 1
Daniel_Kamel
  • 610
  • 8
  • 29
  • Your Map takes constant space, so you just have to eliminate your output array. You can update the input array instead. BTW, you can make your code simpler by using an array of length 3 instead of your Map to compute the frequencies. – Eran Oct 07 '19 at 10:38
  • (Not sure if that is the best duplicate. Practically it is kind of a classic problem by Dijkstra: https://en.wikipedia.org/wiki/Dutch_national_flag_problem) – tevemadar Oct 07 '19 at 10:41
  • @Eran you're right, thanks mate,i don't know why I just couldn't think of that :/ – Daniel_Kamel Oct 07 '19 at 10:50

1 Answers1

2

If you want just the final result, you can do it using three counters.

  1. Count the number of 1, 2, and 3 on the list.
  2. Then using a loop, from the first of the list, write the digit with the found counted number

As an example, you have 2 1, 2 2, and 3 3. Then you loop over the array and write these numbers from the first of array base on the value of the counter for each number.

The extra space is three variables which is a constant space. Also, the time complexity is Theta(n) as we loop through the array two times.

OmG
  • 18,337
  • 10
  • 57
  • 90