Design a simple dating system like Tinder with the following features:
- Register a user with their gender, age, preferences, and interests.
- Find matching users according to their preferred gender, preferred age range, and common interests.
Implement the Tinder
class:
Tinder()
Initializes the object.void signup(int userId, int gender, int preferredGender, int age, int minPreferredAge, int maxPreferredAge, List<String> interests)
Registers a user with the given attributes.List<Integer> getMatches(int userId)
Returns the top5
matches for the given user. The returned matches should satisfy the following:- The returned user’s gender should equal the given user’s
preferredGender
. - The returned user’s age should be between the given user’s
minPreferredAge
andmaxPreferredAge
(inclusive).
- The returned user’s gender should equal the given user’s
There should be at least
1
common interest between the returned user and the given user.- The results should be sorted in decreasing order by the number of common interests. If there is a tie, it should be sorted in increasing order by
userId
.
- The results should be sorted in decreasing order by the number of common interests. If there is a tie, it should be sorted in increasing order by
If there are fewer than
5
matches, return as many as possible.- Note that the given user might not necessarily be a match for the returned users.
Example 1:
Input
["Tinder", "getMatches", "signup", "getMatches", "signup", "getMatches", "getMatches", "signup", "signup", "getMatches", "signup", "getMatches", "getMatches", "signup", "getMatches", "getMatches"]
[[], [1], [1, 0, 1, 25, 20, 30, ["Singing", "Dancing", "Reading", "Skating"]], [1], [2, 1, 0, 27, 23, 30, ["Painting", "Basketball"]], [1], [2], [3, 1, 0, 25, 20, 30, ["Singing", "Skating"]], [4, 1, 0, 25, 20, 30, ["Singing", "Writing", "Coding"]], [1], [5, 1, 0, 31, 24, 37, ["Singing", "Dancing", "Reading", "Skating"]], [1], [5], [6, 0, 1, 30, 25, 33, ["Volleyball", "Skating"]], [5], [6]]
Output
[null, [], null, [], null, [], [], null, null, [3, 4], null, [3, 4], [1], null, [1, 6], [3, 5]]
Explanation
Tinder tinder = new Tinder();
tinder.getMatches(1); // return [], there is no user with userId 1.
tinder.signup(1, 0, 1, 25, 20, 30, ["Singing", "Dancing", "Reading", "Skating"]);
tinder.getMatches(1); // return [], no users besides user 1 have signed up yet.
tinder.signup(2, 1, 0, 27, 23, 30, ["Painting", "Basketball"]);
tinder.getMatches(1); // return [], user 2 has no common interests with user 1, so there are no matches.
tinder.getMatches(2); // return [], similarly, user 1 has no common interests with user 2.
tinder.signup(3, 1, 0, 25, 20, 30, ["Singing", "Skating"]);
tinder.signup(4, 1, 0, 25, 20, 30, ["Singing", "Writing", "Coding"]);
tinder.getMatches(1); // return [3, 4], both users 3 and 4 are in the age range for user 1 and
// are the preferred gender of user 1. Since user 3 has 2 common interests
// and user 4 has 1 common interest, user 3 is returned before user 4.
tinder.signup(5, 1, 0, 31, 24, 37, ["Singing", "Dancing", "Reading", "Skating"]);
tinder.getMatches(1); // return [3, 4], user 5 has an age larger than the maxPreferredAge of user 1.
tinder.getMatches(5); // return [1], user 1 has the preferred age, gender, and has 4 common interests.
tinder.signup(6, 0, 1, 30, 25, 33, ["Volleyball", "Skating"]);
tinder.getMatches(5); // return [1, 6], user 6 has the preferred age, gender, and has 1 common interest.
tinder.getMatches(6); // return [3, 5], users 3 and 5 both have the preferred age, gender,
// and have 1 common interest. Since they both have 1 common interest
// and 3 < 5, user 3 is returned before user 5.
Constraints:
1 <= userId <= 104
0 <= gender, preferredGender <= 1
18 <= age <= 90
18 <= minPreferredAge <= maxPreferredAge <= 90
1 <= interests.length <= 5
1 <= interests[i].length <= 20
interests[i]
consists of lowercase and uppercase English letters and' '
.- All strings in
interests
are unique. - At most
1000
calls will be made tosignup
andgetMatches
. userId
will be unique across all calls made tosignup
.
Hint #1
Create a User class to more easily store each user.
Hint #2
Could you use a data structure to easily map a userId to the class instance?
Hint #3
Find all users that satisfy the conditions before sorting for the top 5.
Solution
import java.util.*;
import java.util.stream.Collectors;
/**
* Your Tinder object will be instantiated and called as such:
* Tinder obj = new Tinder();
* obj.signup(userId,gender,preferredGender,age,minPreferredAge,maxPreferredAge,interests);
* List<Integer> param_2 = obj.getMatches(userId);
*/
public class Tinder {
private static final class User {
private final int userId;
private final int gender;
private final int preferredGender;
private final int age;
private final int minPreferredAge;
private final int maxPreferredAge;
private final List<String> interests;
// 私有构造器,通过 Builder 创建
private User(Builder builder) {
this.userId = builder.userId;
this.gender = builder.gender;
this.preferredGender = builder.preferredGender;
this.age = builder.age;
this.minPreferredAge = builder.minPreferredAge;
this.maxPreferredAge = builder.maxPreferredAge;
this.interests = builder.interests;
}
// Builder 静态内部类
public static class Builder {
private int userId = -1; // 默认值
private int gender = -1; // 默认值
private int preferredGender = -1; // 默认值
private int age = -1; // 默认值
private int minPreferredAge = -1; // 默认值
private int maxPreferredAge = -1; // 默认值
private List<String> interests = new ArrayList<>();
// 构造器无参数,所有字段通过链式调用设置
public Builder() {}
public Builder userId(int userId) {
this.userId = userId;
return this;
}
public Builder gender(int gender) {
this.gender = gender;
return this;
}
public Builder preferredGender(int preferredGender) {
this.preferredGender = preferredGender;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder minPreferredAge(int minPreferredAge) {
this.minPreferredAge = minPreferredAge;
return this;
}
public Builder maxPreferredAge(int maxPreferredAge) {
this.maxPreferredAge = maxPreferredAge;
return this;
}
public Builder interests(List<String> interests) {
this.interests = interests;
return this;
}
// 构建 User 实例
public User build() {
if (userId == -1 || gender == -1) {
throw new IllegalArgumentException("userId and gender are required");
}
return new User(this);
}
}
}
private final Map<Integer, User> userMap;
public Tinder() {
userMap = new HashMap<>();
}
public void signup(int userId, int gender, int preferredGender, int age,
int minPreferredAge, int maxPreferredAge, List<String> interests) {
userMap.putIfAbsent(userId, new User.Builder()
.userId(userId)
.gender(gender)
.preferredGender(preferredGender)
.age(age)
.minPreferredAge(minPreferredAge)
.maxPreferredAge(maxPreferredAge)
.interests(interests)
.build());
}
public List<Integer> getMatches(int userId) {
if (!userMap.containsKey(userId)) {
return Collections.emptyList();
}
User user = userMap.get(userId);
return userMap.values().stream()
.filter(candidate -> candidate.userId != userId) // 排除自己
.filter(candidate -> candidate.gender == user.preferredGender) // 性别匹配
.filter(candidate -> candidate.age >= user.minPreferredAge && candidate.age <= user.maxPreferredAge) // 年龄匹配
.map(candidate -> new AbstractMap.SimpleEntry<>(candidate.userId,
(int) user.interests.stream().filter(candidate.interests::contains).count())) // 统计共同兴趣数量
.filter(pair -> pair.getValue() > 0) // 至少有一个共同兴趣
.sorted((a, b) -> {
int cmp = Integer.compare(b.getValue(), a.getValue());
return cmp != 0 ? cmp : Integer.compare(a.getKey(), b.getKey());
})
.limit(5) // 最多返回 5 个匹配
.map(AbstractMap.SimpleEntry::getKey) // 提取用户 ID
.collect(Collectors.toList());
}
}