I would like to count the number of unique objects which are inside a particular Vector. For example, I have a class Person which has Vector<Person> family. I 'm trying to find a way to count the length of the extended family. There could be relations between people such as:-
Mike is related to Pete;
Mike is related to John;
John is related to Amy;
Mike would have an extended family of 4 (which includes himself).
I figured the only way to do this is with recursion and I have something like this so far.
public int getExtendedFamily(Person person) {
// Add the current person if he/she does not exist
if (!(lineage.contains(person))) {
lineage.add(person);
// If the person has no direct family
if (person.getFamily().size() == 0)
return lineage.size();
else {
// Otherwise iterate through the family members
for (Person familyMember : person.getFamily()) {
return lineage.size() + getExtendedFamily(familyMember);
}
}
} else {
// Person already exists...
return lineage.size();
}
return 0;
}
I've created a new vector lineage to keep track of the unique people I come across.
Obviously I know I'm some way off with this code as my lineage.size() isn't right. I just can't get my head around how to structure the recursion, Any guide would be appreciated. Even if it's just pseudocode!
Kind Regards,
Ben
updated code, appears to work
public int getExtendedFamily(Person person) {
// If the person exists just return counter,
//and go back up the call stack;
if ((lineage.contains(person))) {
return counter;
} else {
// Otherwise add the person to the lineage data structure
// and continue
lineage.add(person);
// Loop through current persons family
for (Person family_member_ : person.getFamily()) {
// If the current family member index is not in the lineage
// then increase the counter and recursively call getExtendedFamily,
// to count that persons unique family members.
if (!lineage.contains(family_member_)) {
counter++;
getExtendedFamily(family_member_);
};
}
}
return counter;
}
It would probably just be the vector's size plus one, assuming the relationships are all saved.
If you are getting into generations, where the descendants are not reported in the grandparent, the recursive way to do it would be to return the size of the vector and return if there are no children.
If there is no requirements that the relationships are fully saved, pass a set to the recursive function and save to the set. Return when the vector is 0.
Related
New to programming, please forgive if this is stupid
I'm trying to loop through two arrayLists at once in Java. Below is my code and beneath that is the code I am trying to implement (if this is possible).
In a class "Tournament", it creates and stores Champion objects. I have two arrayLists: championList(this stores all hard coded champion objects into the game) and teamList(champion objects are added to a players team).
I want to check if the champion object in question (the parameter in the method) exists by looping through both arrayLists and returning a specified int if it doesn't.
Working code:
public int retireChamp(String nme){
for(Champion temp: championList)
{
if(temp.getName().equals(nme))
do something etc...
}
Code I want to implement if possible
public int retireChamp(nme){
for(Champion temp: championList && teamList)
{
do something...
}
If I understand correctly, your lists do not always seem to contain the same elements, and if they do, not necessarily in the same order. What you actually want to do is not iterate over the two lists at the same time but check if there is an element in both lists that has the same attribute as the passed parameter. You can do this one after the other:
public int retireChamp(nme){
boolean inChampList = false;
boolean inTeamList = false;
for(Champion temp: championList) {
if(temp.getName().equals(nme)){
inChampList = true;
break;
}
}
for(Champion temp: teamList) {
if(temp.getName().equals(nme)){
inTeamList = true;
break;
}
}
if(inChampList && inTeamList) {
//your logic here - nme is in both lists
} else if (inChampList ^ inTeamList) {
//your logic here - nme is in one of the lists
} else {
//your logic here - nme is in none of the lists
}
}
Just had a phone interview with TripAdvisor (and didn't make the cut).
I was given the code below and asked to implement findBestTravelAlert (in Java).
Given a list of TravelAlert objects, find the best travel alert to display for a specific location. See example at http://www.tripadvisor.com/Tourism-g147306-Haiti-Vacations.html
class TravelAlert {
int id;
String message;
int locationId;
}
class Location {
int locationId;
int parentLocationId; // -1 if no parent, location is hierarchy
String name;
static Location findLocation(int locationId) {...}
}
class TravelAlertStore {
private List<TravelAlert> lAlerts; // already populated, static
// Return null if no alert
TravelAlert findBestTravelAlert(int locationId) {
// implement this
}
}
Examples: If we have 3 travel alerts, one in Boston, one in Massachusetts, and one in the USA:
A user looking at a Boston specific page should see the travel alert of Boston and not the one of Massachusetts
A user looking at a Massachusetts page should see the travel alert of
Massachusetts
A user looking at a Newton specific page should see the
travel alert of Massachusetts
A user looking at a NYC specific page
should see the US travel alert
A user looking at a Montreal specific
page should see no travel alert.
The way I did it was rather naive, but it was all I could come up with under pressure:
Search through the list of TravelAlerts and see if the locationId matches that of our locationId. If not, repeat the search and check for matches with the locationId of the parent. If at any point in this process we find a match, return that TravelAlert. If we reach the end of the process (i.e. there is no parent location), return null.
Here's the code:
TravelAlert findBestTravelAlert(int locationId) {
TravelAlert current_alert = searchList(locationId, lAlerts);
if(current_alert != null) {
return current_alert;
}
else {
int parentLocationId = findLocation(locationId).parentLocationId;
if(parent_locId == -1)
return null;
else {
return findBestTravelAlert(parentLocationId);
}
}
}
TravelAlert searchList(int locationId, List<TravelAlert> cur_list) {
if(cur_list == null) {
return null;
}
else if(cur_list.locationId == locationId) {
return cur_list;
}
else {
searchList(locationId, cur_list.next())
}
}
The time complexity is O(nk), where n is the length of the List of TravelAlerts and k is the height of the location hierarchy tree.
So, my question is:
Is there a better algorithm for doing this, and
Is there a better way of implementing my algorithm?
I'm sure the answer to the second question is yes; there must be built-in methods I could have used, were I more familiar with Java.
Any help would be appreciated. Good luck to all future applicants!
1) Your searchList() method doesn't work (or even compile). There is no locationId field on List, and when you attempt to make the recursive call you are trying to pass an element from the list into the second parameter, where the list is expected.
2) You haven't followed either the Sun de-facto standard coding conventions, or the coding conventions of the example.
3) Generally, recursion is less efficient than looping (because you have to keep lots of stack frames around instead of, say, a single pointer/index into an array) - and since both of your recursive functions are tail-recursive they could both be replaced by loops.
Without building a better data structure (e.g. a Map of location id to travel alert), or knowing that the list of travel alerts is sorted (which you would probably have gained some credit for mentioning), you could probably save some time by pre-computing the list of location ids (that is, the chain from the location to the top of the tree) and then walking the travel alert list once (assuming it's considerably bigger than the depth of the location tree) and comparing each alert with the list of location ids to determine the best match.
Using what dty has said, I went and coded the example to see how it would look.
The first step is to convert the List into a hashMap. The idea is that it takes O(N) to complete this mapping, but after that it is O(1) to lookup a location to see if there is a valid TravelAlert.
Also, as dty pointed out, recursion loads the stack heavily. A simple while() loop can be used to step through the locationId and all of the potential parentIds.
// Return null if no alert
public TravelAlert findBestTravelAlert(int locationId) {
TravelAlert result = null;
// Convert list to map
HashMap<Integer,TravelAlert> alertMap = new HashMap<Integer,TravelAlert>();
for (TravelAlert a : lAlerts) {
alertMap.put(a.locationId, a);
}
// search the map with the given locationId as well as parentIds of the locationId
while (result == null && locationId > 0) {
result = alertMap.get(locationId);
locationId = Location.findLocation(locationId).parentLocationId;
}
// TravelAlert returned
// if there are no more parentIds, result will still be null
return result;
}
I know this is late, but I tried coming up with my solution. It recursively checks parents in the list till the parent becomes -1. Order of O(n)
class TravelAlertStore {
private List<TravelAlert> lAlerts;
TravelAlert getLAlert(int locationId) {
for (TravelAlert t : lAlerts) {
if(t.locationId == locationId)
return t;
}
return null;
}
int findHierarchy(int locationId) {
if(lAlerts.contains(locationId))
return locationId;
int parentLocationId = Location.findLocation(locationId).parentLocationId;
if(parentLocationId == -1)
return -1;
return findHierarchy(parentLocationId);
}
TravelAlert findBestTravelAlert(int locationId) {
int bestLocation = findHierarchy(locationId);
return bestLocation > -1 ? getLAlert(bestLocation) : null;
}
}
You could speed it up quite a bit if you attached the alerts to your location tree. For example (dunno what syntax S.O. thinks this is in...):
+ World
+ Canada
- Montreal
+ United States [A!]
+ Massachusetts [B!]
- Boston [C!]
+ New York
- Albany
- New York City
Then, provided you can map a web page to a node in your location tree, all you have to do is work your way up the tree looking for travel alerts. If you get to the top without seeing any, there aren't any to display. This'll take your runtime down to O(k), where k is the height of the tree.
I wrote this version of a solution without looking at anyone's answer. Then I looked at the answers and I think Remy's might be better, but it's hard to say because it depends on the data set.
Remy's version does not even call the look up for the parent locations if there is a match for the child location, which is a good thing if looking up locations takes time.
My version looks up the locations and all parent locations first and gives them weights. Then, it traverses the list of alerts and records the best match it found so far along the way. If it gets to something with a weight of zero, it stops traversing and returns immediately.
If doing the location lookup was fast (i.e. also a HashMap) I think my version COULD be better in the situation where there are a ton of travel alerts, and possibly more than one "best match", since you will not have to traverse the first list.
For example there might be 500 entries for Boston. 10,000 for MA. 500,000 for USA. If you are on the Boston page, as soon as you hit one for Boston the method will return.
But, if looking up a location is expensive, Remy's could be better. Because mine looks up all the parents before starting to traverse the list.
TravelAlert findBestTravelAlert(int locationId) {
// LocationID mapped to weight (0 is best)
HashMap<Integer,Integer> pref = new HashMap<Integer,Integer>();
int weight=0;
while (locationId != -1)
{
Location loc = Location.findLocation(locationId);
if (loc == null) {
// Possibly log an error but don't give up yet
break;
}
pref.put(locationId,weight);
weight++;
locationId = loc.parentLocationId;
}
if (pref.size() == 0) {
throw new InvalidArgumentException(String.Format("Could not locate location with id {0}", locationId));
}
TravelAlert best=null;
int bestWeight=Integer.MAX_VALUE;
foreach(TravelAlert ta in lAlerts) {
Integer wt = pref.get(ta.locationId);
if (wt != null && wt < bestWeight)
{
bestWeight = wt;
best=ta;
}
if (bestWeight == 0) break;
}
return best;
}
This is a recursive solution that may not be the most efficient but will get the job done.
TravelAlert findBestTravelAlert(int locationId) {
for (TravelAlert alert : lAlerts {
if (alert.locationId == locationId) {
return alert;
}
}
int parentId = Location.findLocation(locationId).parentLocationId;
if (parentId == -1) {
return null;
}
return findBestTravelAlert(parentId);
}
I have a binary tree made with the following constructor:
public Person(String name, int age, char gender, Person c1, Person c2)
where c1 is the left child and c2 is the right child.
I want to write a method that searches for a particular name within a maximum generation. So like a.depthFirstSearch(Eva, 1); where Eva is the name to search for and 1 is the maximum number of generations (or levels) I can look into.
Here's what I have:
EDIT:
public Person depthFirstSearch(String name, int maxGeneration)
{
{
Person temp;
if (maxGeneration>1){
if (this.name.equals(name)){
temp=this;
return temp;
}
else{
if (child1!=null)
temp=child1.depthFirstSearch(name, maxGeneration-1);
if (child2!=null)
temp=child1.depthFirstSearch(name, maxGeneration-1);
}
}
return null;
}
}
There's two problems here. I think depth gets reset to 0 every time the function calls itself, so I know I can either keep track of depth somewhere else or find an alternative. The other problem, I think, is that child2 is never really reached, since I return at child1. I'm not really sure how this works so if someone could explain that, that'd be great. Any suggestions for some fixes?
Also, I'm told that I have to search depth first, meaning looking into the deeper generations first. I'm not really sure what that means and how different it is from the logic I'm using in my implementation.
Since you decrement maxGeneration in each recursive call, you don't need the depth variable at all: when maxGeneration == 0 you simply don't search any more and return null.
As for your other problem, instead of directly returning the value of child1.depthFirstSearch(...), store the value in a temporary variable. If it is not null, you have found the node, so return it immediately, otherwise continue searching under child2.
Update:
It should be if (maxGeneration >= 1) ... (greater than or equal to), otherwise the last call with maxGeneration == 1 will always return null. Alternatively, you can just check for 0 and return null:
if (maxGeneration == 0)
return null;
// rest of your code
Also, you still aren't using the return value to check if the node was actually found in the left subtree or not. Right now, even if you find the node under child1, you still look under child2 and you will end up returning null, which is wrong. You need to search under child2 only if the left search returned null:
Person temp;
if (child1 != null) {
temp = child1.depthFirstSearch(name, maxGeneration-1);
if (temp != null)
return temp; // found the node, just return
}
// otherwise the following code will execute
if (child2 != null) {
temp = child2.depthFirstSearch(name, maxGeneration-1);
if (temp != null)
return temp; // found the node, just return
}
// didn't find node under either child
return null;
I need a class Person to describe persons. Each person has a name and an array consisting of Person-objects, which represent the person's children. The person class has a method getNumberOfDescendants, which returns an integer equal to the total number of descendants of the person, i.e. his children plus grandchildren plus their children etc. Is there a simple way to do this using recursion?
What if you want to count the descendants in a certain generation only? In other words, getNumberOfDescendants(int generation) would return the number of children if generation=1, number of grandchildren if generation=2 etc.
Sure.
public class Person {
private Person[] myChildren;
public int getNumberOfDescendants() {
if (myChildren == null || myChildren.length==0) return 0;
int myDescendants = 0;
for (Person child:myChildren) {
myDescendants += 1; // for this particular child itself
myDescendants += child.getNumberOfDescendants(); //add the child's children, grandchildren, etc.
}
return myDescendants;
}
}
getNumberOfDescendants()
{
int sum = 0;
for (int n=0; n < descendants.length; n++)
{
sum += 1 + descendants[n].getNumberOfDescendants();
}
return sum;
}
Note that the "1 +" is the only place where we're actually increasing the count. That line gets called once for every descendant in the tree.
It's not really recursion, per se, but an instance of the class could sum the results of calling the getNumberOfDescendants() method for each of its children.
Alternatively, you could make this method faster by having each instance notify its parent whenever it got a new descendant (either a new child or from being notified by a child). That way, its count of the number of descendants would always be up-to-date.
public int getNumberDescendents()
{
int nDesc = 0;
if (descendants != null)
{
for (Person p : descendants)
{
nDesc++; // this child
nDesc += p.getNumberDescendents(); // this child's desc
}
}
return nDesc;
}
By the time I wrote the example up, others had posted basically the same thing, so I am kind of redundantly posting.
I'm having trouble working out how to count instances of Values in a HashMap.
I have seen that there is methods attached to the Object class that look as if they are able to help me, so I've tried to cast those in to work but I must be doing something wrong somewhere.
If there's an easier way, I haven't found it yet. NB: Library is my HashMap.
public void borrowBooks(String id, String name, String sid, String sname) {
if((getKeyFromValue(Books, name).equals(id))&&(getKeyFromValue(Students, sname).equals(sid))){
if((Object)Library.countValues(sid)!=5){
Library.put(id, sid);
}
else{
System.out.println("You have exceeded your quota. Return a book before you take one out." );
}
}
}
Which doc are you looking at ? The Javadoc for Hashmap doesn't specify a countValues() method.
I think you want a HashMap<String, List<String>> so you store a list of books per student (if I'm reading your code correctly).
You'll have to create a list per student and put that into the HashMap, but then you can simply count the entries in the List using List.size().
e.g.
if (Library.get(id) == null) {
Library.put(id, new ArrayList<String>());
}
List<String> books = Library.get(id);
int number = books.size() // gives you the size
Ignoring threading etc.
First: There is (almost) no point in ever casting anything to Object. Since everything extends Object, you can always access the methods without casting.
Second: The way you're casting actually casts the return value, not the Library. If you were doing a cast that was really necessary, you would need an extra set of parentheses:
if(((Object)Library).countValues(sid) != 5)
Third: There is no countValues method in either HashMap or Object. You'll have to make your own.
This is the general algorithm to use (I'm hesitant to post code because this looks like homework):
initialize count to 0
for each entry in Library:
if the value is what you want:
increment the count
int count = 0;
for(String str : Library.values())
{
if(str == sid)
count++;
if(count == 5)
break;
}
if(count < 5)
Library.put(id, sid);
else
System.out.println("You have exceeded your quota. Return a book before you take one out." );