Google Interview Question for Java Developers


Country: United States
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
5
of 5 vote

public boolean isCriteriaSuccess( String s1) {
System.err.println( " Calling "+s1);
if ( s1 == null) return false;
if ( s1.length() == 1 ) return true;
if ( !inDict(s1)) return false;
System.err.println( " Calling recursively "+s1);
boolean retValue = false;
int strLength = s1.length();
for ( int i = 0;i < strLength ;i++) {
retValue = retValue || (isCriteriaSuccess(s1.substring(0,i)+s1.substring(i+1,strLength)));

}
return retValue;

}

- thomascom136 August 03, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Why using || and not && on recursive returns?

- Mark August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

this approach is correct...

it should be substring(0, i-1) + substring(i+1, n), because here need to remove one character that is ith element

- algos August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

the substring process is correct as he wrote

(isCriteriaSuccess(s1.substring(0,i)+s1.substring(i+1,strLength)));

substring works with this subset [first,last[ it means that the last is not included.


i still don't get why he put an OR and not an AND in the recursive call

- Anonymous August 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Using and OR is correct since we need to find if a such a sequence exists by removing one character at a time.
For example restated -> restate -> estate -> state -> stat -> sat -> at -> a
This chain is obtained by removing d from restated
Such a chain might not exist for say removing 2nd alphabet since "rstated" is an invalid word and should return false

- Nomad August 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
1
of 3 votes

||'ing is correct, except its highly inefficient, if finding one such sequence of words is enough.

Its like exploring all the paths in a tree, even after 1 path lead to the solution.

As soon as one of the recursive calls inside the for loop returns true, we are done! we can return true and set of words visited through that iteration(recursively).

- X August 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

It sounds correct to me, but it should be better if we can avoid testing duplicated sub-words. For example for this original word, minimize, we are no need of running the function to test "mi" twice.

- Ngoc August 17, 2013 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

i think above code is correct and telling that weather we can make valid dictionary word by breaking giving word....but in your for loop...u are processing some substrings again and again..which is inefficient i think.... following is java code which printing all valid world from dictionary(or we can modified following code if u want only bool value)...my point is making for loop efficient(only processing one substring one time)...correct me if i wrong..or my code is wrong

public void removeword(String s,int j){
        int i;
        if(s==NULL)
            return;
        if(s.length()==1){
            System.out.println(s);
            return;}
        if(dic.contain(s))
           System.out.println(s);
        for(i=j;i<s.length();i++){
             removeword(s.substring(0,i)+s.substring(i+1,s.length()),i);
        }   
    
    }

- dhamu.31954 October 01, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

|| is used because he has taken retValue = false
You can use && but then you have to set retValue = true

- nitesh.kedia5 March 01, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Actually it is not that inefficient, cuz once it found a true path, it will immediately return the final result instead of continuing searching, because this "retValue=retValue || isCriteriaSuccess()" won't call the function if retValue is already true. This is exactly how "OR" works

- nicolastree23 March 02, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

What is the time complexity for this recursion method?

- Anonymous March 03, 2015 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

If the number of query words is large and dictionary is static, here is what I propose:

Preprocessing:
Create a graph of all the dictionary words. Each word will get a node and there will be an edge between 2 nodes (or words) if one of the words is only one alphabet lesser than the other word. This should take O(M^2) time, but for practical purpose we can assume the number of words in dictionary are constant, so it could be assumed as a constant time preprocessing operation. (Note that M is the number of dictionary words)

Now to search if a word can be broken down to smaller words (until the word becomes null) do this:
1. Find the word in the graph. Let this node is called N(word). This step takes O(M) time where M is the number of dictionary words.
2. Do a depth first or breadth first traversal starting at N(word). You can stop traversing when you find a node with length zero and return True. (You'll only to traverse at most lengthOf(word) deep nodes from N(word)). If you couldn't reach a node with length 0, return False.
If L is the length of the query word, this step will take O(L*L) worst case time.

- Epic_coder August 03, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

That preprocessing is not O(M^2) but O(M^2 * L^2) because you're testing all pairs of words and to check if one word is only missing 1 letter from the other takes O(L^2).
This can be reduced to O(M * L^2) using a hash table. For every word, check all possibilities to remove 1 letter and check if the resulting string appears in the dictionary (using the hash table). Checking all possibilities takes O(L^2) for all M words.

- Miguel Oliveira August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

We don't bother about pre-processing (constructing dictionary). In problem it is mentioned that a function() is available which gives us whether the word is in dictionary or not. So, this is out of problem scope.

Now coming to actual problem, I vote for recursion + dynamic programing APPROACH which is given by thomoscom136.

- Kallu August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

This one looks interesting. The edges should be directed, i.e. only from restated -> restate and not the other way around. And the finding of tree height can be done recursively.

- horizon August 09, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Nice approach, but:

1- You are assuming a set of "M" words is given to you. The question says, "you are given a test function to determine whether a given word is in the dictionary."

2- Given the "test function" you do not need the graph. Start from the given word of length "L". Check all the possibilities of dropping a letter (L - 1) and put a vertex for each valid case. Repeat until the graph is made. It seems like L! but it will be less.

The idea is that if you are given a word with "L" letters, there is at most 2^L - 2 words of length < L. Including the given word and the "null" string, 2^L (total number of subsets of a set with "L" elements).

So the initial step in you algorithm should be to build a graph with O(2^L) nodes, and run the algorithm. This takes O(2^L). The DFS and BFS also take O(2^L) so the complexity is O(2^L).

To compare it with a simple recursive algorithm we should note that through recursion we check for repeated words, (i.e., in "restated" dropping "r" then "d" or "d" then "r" is the same). So the complexity is O(L!) >> O(2^L).

Also, the time complexity of O(2^L) is quite nicely compatible with the predictions from information theory. We know that the entropy of English alphabet is somewhere around 1.5 bits per character, i.e., there is a total of 2^(1.5 L) words of length "L". Since we are looking for the ones made with the given "L" letters, the complexity should be less, but not super-exp in "L".

I wonder if this problem is "NP"-complete in size of input.

- Ehsan August 21, 2013 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

Java Implementation of remove word using dynamic programming...

public class RemoveWord {

	Map<String, Boolean> memorize;
	
	public RemoveWord() {
		super();
		memorize = new HashMap<String, Boolean>();
	}
	
	public boolean remove(String word, Set<String> dictionary) {
		if (word == null){
			return false;	
		}
		else if (word.length() == 1){
			return true;
		}
		else if (!dictionary.contains(word)){
			return false;
		}
		else {
			if(memorize.containsKey(word)){
				return memorize.get(word); 
			}
			else{
				boolean isValid = false;
				for ( int index = 0; index < word.length(); index++) {
					isValid = isValid || removeWord(word.substring(0, index)+ word.substring(index+1), dictionary);
				}
				memorize.put(word, isValid);
				return isValid;
			}
		}
	}

	public static void main(String[] args) {
		Set<String> dictionary = new HashSet<String>();
		dictionary.add("restated");
		dictionary.add("restate");
		dictionary.add("estate");
		dictionary.add("state");
		dictionary.add("stat");
		dictionary.add("sat");
		dictionary.add("at");
		
		RemoveWord obj = new RemoveWord();
		System.out.println(obj.remove("restated", dictionary));
	}	
}

- Adnan Ahmad October 02, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Yes it can be done using dynamic programming. The problem here is not to check whether the word is in the dictionary or not. The problem is used to determine whether by taking out one alphabet at a time the remaining word is in the dictionary or not. Now this can be easily done by using dynamic programming or recursion. Here is the idea

#include <iostream>
#include <string>
using namespace std;

bool dictionaryContains(string str)
{
     string dictionary[] = {"restated","restate","estate","state","stat","sat","at","a" };
    int size=sizeof(dictionary)/sizeof(dictionary[0]);
    for(int i=0;i<size;i++)
    {
        if(dictionary[i].compare(str)==0)
        {
                return true;
        }
    }
    return false;
}
bool wordBreak(string str,int temp)
{
    int size=str.size();
    if(size==0)
        return true;
    for(int i=1;i<=size;i++)
    {
        if(dictionaryContains(str.substr(0,temp))&&wordBreak(str.substr(0,temp-1)))
            return true;

    }
    return false;
}
int main()
{
    string str="restated";
    int n=str.size();
    if(wordBreak(str,n-1))
        cout<<"Can be broken";
    else
        cout<<"Cant be broken";
}

- vgeek August 04, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Are you deleting any middle elements?

- Anonymous August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

How does this

if(dictionaryContains(str.substr(0,temp))&&wordBreak(str.substr(0,temp-1)))

compile ?

- Anonymous September 13, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Just wanted to understand one thing. Isn't the requirement of the problem to check if each word formed by removal of a character is a word again?
i.e say ABCDxPQRS is a word. Then we need to confirm whether ABCDPQRS is a word or not? Similarly for other removals.
Right?

- Learner August 04, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

dict = ['restated','restate','estate','state','stat','sat','at','a']

def removeWords(string):
    l=[]
    for i in range(len(string)):
        ns = string[0:i]+string[i+1:]
        if ns in dict:
            l = l +[ns]
    return l


q = removeWords('restate')
size = len('restate')-1
flag = 0
while len(q)>0 and size > 1:
    qnew = []
    for a in q:
        qnew = qnew + removeWords(a)
    size = size -1
    if len(qnew)==0:
        flag = 1
        break;
    else:
        q = qnew


if flag=0 and size==1:
    print true

- Anonymous August 04, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

use dfs

- Anonymous August 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

import java.util.Arrays;
import java.util.List;

public class strCriteria {
public static void main(String args[])
{
String a="restat";
System.out.println(check(a,0,a.length()));
}
public static boolean findWord(String a)
{
List<String> st = Arrays.asList("restated","restate","estate","state","stat","tat","at","a");
if(st.contains(a))
return true;
return false;
}
public static boolean check(String a,int beg,int end)
{
if(beg>=end)
return true;
if(findWord(a.substring(beg, end)))
return check(a,beg+1,end) || check(a,beg,end-1);
return false;
}
}

- Anonymous August 08, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

#include <string>
#include <vector>
using namespace std;

int main(void)
{
char a[] = "restated";
unsigned int i, j;
char window[100];
vector<string> validWord; // will contains the vaid dictionary words

for(i = 1; i < strlen(a); i++)
{
for(j = 0; j <= strlen(a) - i; j++)
{
memcpy(window, a + j, i);
window[i] = 0;
if(IsInDictionary(window))
validWord.push_back(&window[i]);
}
}
return 0;
}

- wee August 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

import java.util.HashSet;


public class RandomWord {

    public static void main(String[] args){

        String str = "restated";
        System.out.print(checkword(str));



    }
    public static boolean checkword(String str){

        if(str.length()==1)
            return true;

        for(int i=0;i<str.length();i++){

            String first = str.substring(0,i);
            String last = str.substring(i+1);
            String word = first+last;

            if(isValidWord(word)){
                System.out.println(word);
                if(checkword(word)){
                    return true;
                }else{
                    continue;
                }

            }


        }

        return false;
    }

    public static boolean isValidWord(String str){

        HashSet<String> wordSet = new HashSet<>();
        wordSet.add("restate");
        wordSet.add("estate");
        wordSet.add("state");
        wordSet.add("stte");
        wordSet.add("stat");
        wordSet.add("sat");
        wordSet.add("at");
        wordSet.add("a");

        return wordSet.contains(str);


    }

}

- Saikat September 14, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

This can be done using DP

The recursion looks something like this:
Keep an index to the first and last char of the string say, beg and end

Now in every function call recurse using these two calls func(str, beg, end-1) and func(str, beg+1, end) , if beg==end return

int getSubWords(String str, int beg, int end) {
if(beg == end) {
return isWord(str.charAt(beg)) ;
}

return( isWord(str.substr(beg, end +1) + getSubWords(str, beg+1, end) + getSubstr(str, beg, end-1)));
}
This can be converted into DP by using a 2d memo array for keeping a count of the number of words found.

- scorpionnishme August 03, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

You can delete a char in the middle, and the search would have to use like "s" + "at" after deleting a 't' in "stat". So I don't think this approach works.

- Miguel Oliveira August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Hi scorpionishime can you please let me know how to convert to a dp by taking a 2d arrray

- DashDash August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Oh I think I misread the question, I thought the words needed to be a substring.

If the sub words do not need to be of consecutive characters, the recursion will look something like this:

Either a character will be a part of the solution or not.

str = original string
index = current string index
currWord: current set of alphabets which are a contender for a word

getSubWords(String str, int index, String currWord)
{
if(index < 0) {
return (isWord(currWord));
}

return ( isWord(currWord) + getSubWords(str, index-1, str.charAt(index)+currWord) + getSubWords(str, index-1, currWord))
}

- scorpionnishme August 04, 2013 | Flag
Comment hidden because of low score. Click to expand.
-2
of 2 vote

If I understand problem correctly, "sat" should not be the correct sub word of "restated".

- Kallu August 04, 2013 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More