patternjavaMinor
Programming challenge "Friend Request in Social Network"
Viewed 0 times
socialchallengerequestprogrammingfriendnetwork
Problem
I am trying to solve a programming problem on a coding platform. When I execute it on my PC, it works perfectly, but when I submit the code on the coding platform, it throws a "Time Limit Exceeded" error. Can someone check my solution and help optimize it?
In a social network, a person can invite friends of his/her friend.
John wants to invite and add new friends. Complete the program below
so that it prints the names of the persons to whom John can send a
friend request.
Input format:
The first line contains the value of the N which represent the number
of friends. N lines contain the name of the friend F followed by the
number of friends of F finally their names separated by space.
Input:
Output:
Explanation:
Ram is not present in the output as Ram is already John's friend.
My Approach
And can we solve this problem using graph/trees. The problem statement and my code can be found here.
`import java.util.HashSet;
import java.util.Scanner;
import java.util.StringTokenizer;
class Ideone {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // No of friends
sc.nextLine();
HashSet hs = new HashSet<>(); // to store name of the John's friends
String invitation = "";
for(int i =0; i
In a social network, a person can invite friends of his/her friend.
John wants to invite and add new friends. Complete the program below
so that it prints the names of the persons to whom John can send a
friend request.
Input format:
The first line contains the value of the N which represent the number
of friends. N lines contain the name of the friend F followed by the
number of friends of F finally their names separated by space.
Input:
3
Mani 3 Ram Raj Guna
Ram 2 Kumar Kishore
Mughil 3 Praveen Naveen Ramesh
Output:
Raj Guna Kumar Kishore Praveen Naveen Ramesh
Explanation:
Ram is not present in the output as Ram is already John's friend.
My Approach
- Extract the first word of each line and store them in
HashSetand remove them from the string. Names stored inHashSetare already friends of the person (John).
- Now extract the names from the String using
StringTokenizerand check whether the name is contained in theHashSet. If it is not present then print it.
And can we solve this problem using graph/trees. The problem statement and my code can be found here.
`import java.util.HashSet;
import java.util.Scanner;
import java.util.StringTokenizer;
class Ideone {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // No of friends
sc.nextLine();
HashSet hs = new HashSet<>(); // to store name of the John's friends
String invitation = "";
for(int i =0; i
Solution
The big performance issue with the current solution is that you're relying on building a
We need another approach to the problem that doesn't rely on a simple
With that in mind, we can refactor the code to use those data structures:
Notice that I changed other things in there:
At the end of the process, we have our wanted collection inside
If you are on a lower Java version, you would need to write the
String to keep the list of persons that were sent a friend request. A String is immutable in Java so every single operation on it will result in the creation and allocation of a new String. When doing those sorts of repeated allocation in a loop, the performance degrades rapidly.We need another approach to the problem that doesn't rely on a simple
String, and with that, a better data structure.- From the problem description, we need to maintain a collection of the friends of John. To pick a suitable data structure, let's examine what we'll need to do with it: we want to add elements to it (each friend name read), and we want to check whether that collection contains a specific name (to not add it to the list of invited persons). Additionally, we don't care about a particular order for this collection. The perfect data structure for that is a
HashSet, just like the one you used: it has a constant-timeaddandcontainsmethods.
- Then, we also need to maintain a collection of the invited persons, those that were sent the friend request. This is where you used a
Stringand we can do better. Like the above, we want a data structure capable of adding elements (the name of the invited persons), but we also want it to be capable of removing elements (the friend names we might read further down the input). Also, we want to keep an order here, specifically, the order in which the elements were added. For that,LinkedHashSetis perfect:addandremoveare both constant-time operations, and it keeps the insertion order.
With that in mind, we can refactor the code to use those data structures:
Collection friends = new HashSet<>(); // to store name of the John's friends
Collection invited = new LinkedHashSet<>();
for (int i = 0; i < N; i++) {
Scanner scanLine = new Scanner(sc.nextLine());
String friend = scanLine.next();
friends.add(friend);
invited.remove(friend); // potentially remove this invited as it is actually a friend
scanLine.next(); // ignore the number of friends, we can deduce it anyway
while (scanLine.hasNext()) {
String name = scanLine.next();
if (!friends.contains(name)) {
invited.add(name);
}
}
}Notice that I changed other things in there:
- When you have the line of input, that is space-separated, you don't need to read manually characters by characters. You can either
split(" "), which would return an array of all the tokens space separated, or you can use anotherScanner, which by default tokenizes over white spaces, meaning every call toScanner.next()will return the next word.
- The variables have a meaningful name:
friendsrepresent the collection of John's friend andinvitedrepresents the collection of persons to whom John sent a friend request.
At the end of the process, we have our wanted collection inside
invited, so we can finally print it. For that, we can use String.join starting from Java 8, which is built-in.System.out.println(String.join(" ", invited));If you are on a lower Java version, you would need to write the
for loop explicitely and use a StringBuilder to construct the result, like shown here. Don't use the old StringTokenizer, it isn't officially deprecated but it is only kept for compatibility reasons and is considered a legacy class.Code Snippets
Collection<String> friends = new HashSet<>(); // to store name of the John's friends
Collection<String> invited = new LinkedHashSet<>();
for (int i = 0; i < N; i++) {
Scanner scanLine = new Scanner(sc.nextLine());
String friend = scanLine.next();
friends.add(friend);
invited.remove(friend); // potentially remove this invited as it is actually a friend
scanLine.next(); // ignore the number of friends, we can deduce it anyway
while (scanLine.hasNext()) {
String name = scanLine.next();
if (!friends.contains(name)) {
invited.add(name);
}
}
}System.out.println(String.join(" ", invited));Context
StackExchange Code Review Q#136466, answer score: 4
Revisions (0)
No revisions yet.