Puzzle: Find the order of n persons standing in a line (based on their heights)

前端 未结 11 2140
抹茶落季
抹茶落季 2020-12-30 05:58

Saw this question on Careercup.com:

Given heights of n persons standing in a line and a list of numbers corresponding to each person (p) that gives the number of pers

相关标签:
11条回答
  • 2020-12-30 06:19

    The O(nlogn) algoritm is possible.

    First assume that all heights are different.

    Sort people by heights. Then iterate from shortest to tallest. In each step you need an efficient way to put the next person to the correct position. Notice that people we've already placed are not taller that the current person. And the people we place after are taller than the current. So we have to find a place such that the number of empty positions in the front is equal to the inFronts value of this person. This task can be done using a data structure called interval tree in O(logn) time. So the total time of an algorithm is O(nlogn).

    This algorithm works well in case where there's no ties. As it may be safely assumed that empty places up to front will be filled by taller people.

    In case when ties are possible, we need to assure that people of the same height are placed in increasing order of their positions. It can be achieved if we will process people by non-decreasing inFronts value. So, in case of possible ties we should also consider inFronts values when sorting people.

    And if at some step we can't find a position for next person then the answer it "it's impossible to satisfy problem constraints".

    0 讨论(0)
  • 2020-12-30 06:20

    Here is a Python solution that uses only elementary list functions and takes care of ties.

    def solution(heights, infronts):
        person = list(zip(heights, infronts))
        person.sort(key=lambda x: (x[0] == 0, x[1], -x[0]))
        output = []
        for p in person:
            extended_output = output + [p]
            extended_output.sort(key=lambda x: (x[0], -x[1]))
            output_position = [p for p in extended_output].index(p) + p[1]
            output.insert(output_position, p)
        for c, p in enumerate(output):
            taller_infronts = [infront for infront in output[0:c] if infront[0] >= p[0]]
            assert len(taller_infronts) == p[1]
        return output
    
    0 讨论(0)
  • 2020-12-30 06:24

    As people already corrected for original input:

    Heights : A[] = { 5 3 2 6 1 4 }
    InFronts: B[] = { 0 1 2 0 3 2 }
    Output should look like: X[] = { 5 3 1 6 2 4 }
    

    Here is the O(N*logN) way to approach solution (with assumption that there are no ties).

    1. Iterate over array B and build chain of inequalities (by placing items into a right spot on each iteration, here we can use hashtable for O(1) lookups):
      • b0 > b1
      • b0 > b1 > b2
      • b3 > b0 > b1 > b2
      • b3 > b0 > b1 > b4 > b2
      • b3 > b0 > b5 > b1 > b4 > b2
    2. Sort array A and reverse it
    3. Initialize output array X, iterate over chain from #1 and fill array X by placing items from A into a position defined in a chain

    Steps #1 and #3 are O(N), step #2 is the most expensive O(N*logN). And obviously reversing sorted array A (in step #2) is not required.

    0 讨论(0)
  • 2020-12-30 06:28

    I think the approach indicated above is correct. However a critical piece missing in the solutions above are.
    Infronts is the number of taller candidate before the current person. So after sorting the persons based on height(Ascending), when placing person 3 with infront=2, if person 1 and 2 was in front placed at 0, 1 position respectively, you need to discount their position and place 3 at position 4, I.E 2 taller candidates will take position 2,3.

    As some indicated interval tree is the right structure. However a dynamic sized container, with available position will do the job.(code below)

    struct Person{
        int h, ct;
        Person(int ht, int c){
            h = ht;
            ct = c;
        }
    };
    
    struct comp{
      bool operator()(const Person& lhs, const Person& rhs){
          return (lhs.h < rhs.h);
      }  
    };
    
    vector<int> heightOrder(vector<int> &heights, vector<int> &infronts) {
    
        if(heights.size() != infronts.size()){
            return {};
        }
        vector<int> result(infronts.size(), -1);
        vector<Person> persons;
        vector<int> countSet;
        for(int i= 0; i< heights.size(); i++){
           persons.emplace_back(Person(heights[i], infronts[i]));
           countSet.emplace_back(i);
           }
        sort(persons.begin(), persons.end(), comp());
        for(size_t i=0; i<persons.size(); i++){
            Person p = persons[i];
                if(countSet.size() > p.ct){
                    int curr = countSet[p.ct];
                    //cout << "the index to place height=" << p.h << " , is at pos=" <<  curr << endl; 
                    result[curr] = p.h;
                    countSet.erase(countSet.begin() + p.ct);
                }
    
            }
        return result;
    }
    
    0 讨论(0)
  • 2020-12-30 06:32

    Was solving this problem today, here is what I came up with:

    The idea is to sort the heights array in descending order. Once, we have this sorted array - pick up an element from this element and place it in the resultant array at the corresponding index (I am using an ArrayList for the same, it would be nice to use LinkedList) :

    public class Solution {
        public ArrayList<Integer> order(ArrayList<Integer> heights,      ArrayList<Integer> infronts) {
            Person[] persons = new Person[heights.size()];
            ArrayList<Integer> res = new ArrayList<>();
    
            for (int i = 0; i < persons.length; i++) {
                persons[i] = new Person(heights.get(i), infronts.get(i));
            }
    
            Arrays.sort(persons, (p1, p2) ->  {
                return Integer.compare(p2.height, p1.height);
            });
    
            for (int i = 0; i < persons.length; i++) {
                //System.out.println("adding "+persons[i].height+" "+persons[i].count);
                res.add(persons[i].count, persons[i].height);
            }
    
            return res;
        }
    
    
        private static class Person {
            public final int height;
            public final int count;
    
            public Person(int h, int c) {
                height = h;
                count = c;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-30 06:32

    I found this kind of problem on SPOJ. I created a binary tree with little variation. When a new height is inserted, if the front is smaller than the root's front then it goes to the left otherwise right.

    Here is the C++ implementation:

    #include<bits/stdc++.h>
    using namespace std;
    
    struct TreeNode1
    {
        int val;
        int _front;
        TreeNode1* left;
        TreeNode1*right;
    };
    
    TreeNode1* Add(int x, int v)
    {
        TreeNode1* p= (TreeNode1*) malloc(sizeof(TreeNode1));
    
        p->left=NULL;
        p->right=NULL;
        p->val=x;
        p->_front=v;
    
        return p;
    }
    
    TreeNode1* _insert(TreeNode1* root, int x, int _front)
    {
        if(root==NULL) return Add(x,_front);
        if(root->_front >=_front)
        {
                root->left=_insert(root->left,x,_front);
                root->_front+=1;
        }
        else
        {
            root->right=_insert(root->right,x,_front-root->_front);
        }
    
        return root;
    }
    
    bool comp(pair<int,int> a, pair<int,int> b)
    {
        return a.first>b.first;
    }
    
    void in_order(TreeNode1 * root, vector<int>&v)
    {
        if(root==NULL) return ;
    
        in_order(root->left,v);
    
        v.push_back(root->val);
    
        in_order(root->right,v);
    
    
    }
    
    vector<int>soln(vector<int>h, vector<int>in )
    {
        vector<pair<int , int> >vc;
        for(int i=0;i<h.size();i++) vc.push_back( make_pair( h[i],in[i] ) );
        sort(vc.begin(),vc.end(),comp);
    
        TreeNode1* root=NULL;
    
        for(int i=0;i<vc.size();i++)
            root=_insert(root,vc[i].first,vc[i].second);
    
        vector<int>v;
        in_order(root,v);
        return v;
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n;
            scanf("%d",&n);
                vector<int>h;
                vector<int>in;
    
                for(int i=0;i<n;i++) {int x;
                cin>>x;
                h.push_back(x);}
                for(int i=0;i<n;i++) {int x; cin>>x;
                in.push_back(x);}
    
                vector<int>v=soln(h,in);
                for(int i=0;i<n-1;i++) cout<<v[i]<<" ";
                cout<<v[n-1]<<endl;
                h.clear();
                in.clear();
    
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题