Problem

Given a list of full names (each name contains one or more words), sort the list in lexicographic order by the last name (the last token in each string). If two last names are equal, preserve the original relative order (stable sort) or use the full name as a tiebreaker.

Examples

Example 1

1
2
3
4
5
6
7
8
Input:
names = ["Asha Sharma", "Ravi Kumar", "Priya Singh", "Arun Mehta"]

Output:
["Arun Mehta", "Asha Sharma", "Priya Singh", "Ravi Kumar"]

Explanation:
Last names are ["Sharma","Kumar","Singh","Mehta"]; sorted order by last name yields the output above.

Example 2

1
2
3
4
5
6
7
8
Input:
names = ["Anjali Rao", "Anjali Rao Kumar", "Bhavana Rao", "Karan Patel"]

Output:
["Anjali Rao", "Bhavana Rao", "Anjali Rao Kumar", "Karan Patel"]

Explanation:
The last token for the first three names is ["Rao","Rao","Kumar","Patel"]; ties among "Rao" are resolved by full-name comparison or stable order.

Solution

Method 1 - Stable sort with key = last token

Intuition

Sorting by last name reduces to sorting by a key extracted from each string: the final whitespace-separated token. Using a stable sort preserves original order for equal keys.

Approach

  1. Parse each name and extract the last token key = name.split(" ").last().
  2. Sort the list using the extracted key as the comparator key. Use a stable sort or fall back to comparing full names for ties.
  3. Return the sorted list.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

class Solution {
 public:
  vector<string> sortNamesByLast(vector<string> names) {
    stable_sort(names.begin(), names.end(), [](const string& a, const string& b) {
      auto last = [](const string& s) {
        auto pos = s.find_last_of(' ');
        return pos == string::npos ? s : s.substr(pos + 1);
      };
      string ka = last(a), kb = last(b);
      if (ka == kb) return a < b; // tiebreaker
      return ka < kb;
    });
    return names;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
  "sort"
  "strings"
)

func sortNamesByLast(names []string) []string {
  sort.SliceStable(names, func(i, j int) bool {
    partsI := strings.Fields(names[i])
    partsJ := strings.Fields(names[j])
    li := partsI[len(partsI)-1]
    lj := partsJ[len(partsJ)-1]
    if li == lj {
      return names[i] < names[j]
    }
    return li < lj
  })
  return names
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import java.util.*;

class Solution {
  public List<String> sortNamesByLast(List<String> names) {
    Collections.sort(names, new Comparator<String>(){
      public int compare(String a, String b){
        String[] pa = a.split("\\s+");
        String[] pb = b.split("\\s+");
        String la = pa[pa.length-1];
        String lb = pb[pb.length-1];
        if (la.equals(lb)) return a.compareTo(b);
        return la.compareTo(lb);
      }
    });
    return names;
  }
}
1
2
3
4
5
6
class Solution {
  fun sortNamesByLast(names: MutableList<String>): List<String> {
    names.sortWith(compareBy({ it.split(" ").last() }, { it }))
    return names
  }
}
1
2
3
4
5
6
7
8
from typing import List

class Solution:
  def sortNamesByLast(self, names: List[str]) -> List[str]:
    def last(name: str) -> str:
      parts = name.split()
      return parts[-1] if parts else name
    return sorted(names, key=lambda x: (last(x), x))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
pub struct Solution;
impl Solution {
  pub fn sort_names_by_last(mut names: Vec<String>) -> Vec<String> {
    names.sort_by(|a, b| {
      let la = a.split_whitespace().last().unwrap_or("");
      let lb = b.split_whitespace().last().unwrap_or("");
      match la.cmp(lb) {
        std::cmp::Ordering::Equal => a.cmp(b),
        ord => ord,
      }
    });
    names
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
export class Solution {
  sortNamesByLast(names: string[]): string[] {
    return names.sort((a, b) => {
      const la = a.trim().split(/\s+/).slice(-1)[0];
      const lb = b.trim().split(/\s+/).slice(-1)[0];
      if (la === lb) return a.localeCompare(b);
      return la.localeCompare(lb);
    });
  }
}

Complexity

  • Time complexity: O(n log n * m) – Sorting n names where extracting/comparing last tokens takes O(m) in the average length of names.
  • 🧺 Space complexity: O(n) – Sort may use O(n) auxiliary space depending on the language’s sorting implementation.