Before attempting this problem, you should be comfortable with:
Hash Maps - Using key-value stores for O(1) lookups to associate data
Sorting Algorithms - Understanding how to sort arrays using built-in methods
Custom Comparators - Sorting based on criteria other than default ordering
Index Tracking - Maintaining associations between parallel arrays during transformations
1. Hash Map
Intuition
Since all heights are distinct, we can use each height as a unique key to look up the corresponding person's name. By building a hash map from height to name, we can then sort the heights in descending order and retrieve names in the correct sequence.
Algorithm
Create a hash map that maps each height to its corresponding name.
Sort the heights array in ascending order.
Iterate through the sorted heights in reverse order (descending).
For each height, look up the name in the hash map and add it to the res.
Return the res array containing names sorted by height in descending order.
classSolution:defsortPeople(self, names: List[str], heights: List[int])-> List[str]:
height_to_name ={}for h, n inzip(heights, names):
height_to_name[h]= n
res =[]for h inreversed(sorted(heights)):
res.append(height_to_name[h])return res
publicclassSolution{publicString[]sortPeople(String[] names,int[] heights){Map<Integer,String> map =newHashMap<>();for(int i =0; i < heights.length; i++){
map.put(heights[i], names[i]);}Arrays.sort(heights);String[] res =newString[heights.length];for(int i =0; i < heights.length; i++){
res[i]= map.get(heights[heights.length -1- i]);}return res;}}
classSolution{public:
vector<string>sortPeople(vector<string>& names, vector<int>& heights){
unordered_map<int, string> map;for(int i =0; i < heights.size(); i++){
map[heights[i]]= names[i];}sort(heights.begin(), heights.end());
vector<string> res;for(int i = heights.size()-1; i >=0; i--){
res.push_back(map[heights[i]]);}return res;}};
classSolution{/**
* @param {string[]} names
* @param {number[]} heights
* @return {string[]}
*/sortPeople(names, heights){const map ={};for(let i =0; i < heights.length; i++){
map[heights[i]]= names[i];}
heights.sort((a, b)=> a - b);const res =[];for(let i = heights.length -1; i >=0; i--){
res.push(map[heights[i]]);}return res;}}
publicclassSolution{publicstring[]SortPeople(string[] names,int[] heights){var map =newDictionary<int,string>();for(int i =0; i < heights.Length; i++){
map[heights[i]]= names[i];}
Array.Sort(heights);string[] res =newstring[heights.Length];for(int i =0; i < heights.Length; i++){
res[i]= map[heights[heights.Length -1- i]];}return res;}}
funcsortPeople(names []string, heights []int)[]string{
m :=make(map[int]string)for i, h :=range heights {
m[h]= names[i]}
sort.Ints(heights)
res :=make([]string,len(heights))for i :=0; i <len(heights); i++{
res[i]= m[heights[len(heights)-1-i]]}return res
}
class Solution {funsortPeople(names: Array<String>, heights: IntArray): Array<String>{val map = mutableMapOf<Int, String>()for(i in heights.indices){
map[heights[i]]= names[i]}
heights.sort()returnArray(heights.size){ map[heights[heights.size -1- it]]!!}}}
classSolution{funcsortPeople(_ names:[String],_ heights:[Int])->[String]{var map =[Int:String]()for i in0..<heights.count {
map[heights[i]]= names[i]}let sortedHeights = heights.sorted()var res =[String]()for i instride(from: heights.count -1, through:0, by:-1){
res.append(map[sortedHeights[i]]!)}return res
}}
Time & Space Complexity
Time complexity: O(nlogn)
Space complexity: O(n)
2. Sorting the Pairs
Intuition
Instead of using a hash map, we can pair each height with its corresponding name directly. By creating an array of (height, name) pairs and sorting them by height in descending order, we keep the relationship intact throughout the sorting process.
Algorithm
Create an array of pairs where each pair contains (height, name).
Sort the array of pairs by height in descending order.
Extract the names from the sorted pairs to form the result array.
classSolution:defsortPeople(self, names: List[str], heights: List[int])-> List[str]:
arr =list(zip(heights, names))
arr.sort(reverse=True)return[name for _, name in arr]
publicclassSolution{publicString[]sortPeople(String[] names,int[] heights){int n = names.length;Pair[] arr =newPair[n];for(int i =0; i < n; i++){
arr[i]=newPair(heights[i], names[i]);}Arrays.sort(arr,(a, b)->Integer.compare(b.height, a.height));String[] res =newString[n];for(int i =0; i < n; i++){
res[i]= arr[i].name;}return res;}staticclassPair{int height;String name;Pair(int height,String name){this.height = height;this.name = name;}}}
Rather than copying data into pairs, we can sort an array of indices based on the heights they point to. This approach is memory efficient when names are long strings, since we only move integers during sorting rather than entire strings.
Algorithm
Create an array of indices from 0 to n-1.
Sort the indices array using a custom comparator that compares the heights at those indices in descending order.
Build the result by mapping each sorted index to its corresponding name.
classSolution:defsortPeople(self, names: List[str], heights: List[int])-> List[str]:
indices =list(range(len(names)))
indices.sort(key=lambda i:-heights[i])return[names[i]for i in indices]
publicclassSolution{publicString[]sortPeople(String[] names,int[] heights){Integer[] indices =newInteger[names.length];for(int i =0; i < names.length; i++){
indices[i]= i;}Arrays.sort(indices,(i, j)->Integer.compare(heights[j], heights[i]));String[] res =newString[names.length];for(int i =0; i < names.length; i++){
res[i]= names[indices[i]];}return res;}}
publicclassSolution{publicstring[]SortPeople(string[] names,int[] heights){int[] indices =newint[names.Length];for(int i =0; i < names.Length; i++){
indices[i]= i;}
Array.Sort(indices,(i, j)=> heights[j].CompareTo(heights[i]));string[] res =newstring[names.Length];for(int i =0; i < names.Length; i++){
res[i]= names[indices[i]];}return res;}}
funcsortPeople(names []string, heights []int)[]string{
n :=len(names)
indices :=make([]int, n)for i :=range indices {
indices[i]= i
}
sort.Slice(indices,func(i, j int)bool{return heights[indices[i]]> heights[indices[j]]})
res :=make([]string, n)for i, idx :=range indices {
res[i]= names[idx]}return res
}
class Solution {funsortPeople(names: Array<String>, heights: IntArray): Array<String>{val indices = names.indices.sortedByDescending{ heights[it]}return indices.map{ names[it]}.toTypedArray()}}
The problem asks for people sorted by height in descending order (tallest first). A common mistake is to sort in ascending order and forget to reverse the result or adjust the comparator.
Losing the Name-Height Association After Sorting
When sorting heights separately from names, you must maintain a way to retrieve the corresponding name for each height. Using a hash map or pairing heights with indices before sorting prevents this association from being lost.