Practice
Data Structures and Algorithms
Machine Coding Round (LLD)
System Design & Architecture (HLD)
Frontend UI Machine Coding
Resources
Career Advice and Roadmaps
Data Structures and Algorithms
Machine Coding Round (LLD)
System Design & Architecture (HLD)
Backend Development
Frontend Development
Project Ideas for Software Developers
Core Computer Science
Companies
SDE Jobs & Internships
Interview Questions
Compare Companies
IDE
Online IDE
Collaborative IDE

Restaurant Reviews Editorial

DSA Editorial, Solution and Code

Practice Problem Link: Restaurant Reviews

Please make sure to try solving the problem yourself before looking at the editorial.

Problem Statement

A restaurant listing website has asked you to analyze the reviews on its restaurants.
The reviews need to be sorted by how good they are, the best reviews go on top. The goodness a review is determined by the number of times "good words" appear in them. You are given a list of good words.

Given n reviews and m good words, sort the reviews, such that the one with the most good words appears first. For reviews with the same number of good words, maintain the initial order.

Approach

The approach in this problem is to use a simulation for what is said in the statement in a smarter manner. We will basically traverse on the list of reviews and for each review, try to find the number of good words in it by using a HashSet or HashMap to obtain constant lookup times. We can store the pair of {number of good words, i} for the ith review and sort our array in the manner asked in the question using a custom comparator to return the output in the required manner.

Analysis

  • Time Complexity: O(n * m * |word length|)
  • Space Complexity: O(n)

Implementation

C++
vector<string> orderReviews(vector<string> &reviews, vector<string> &goodWords) {
    set<string> words(goodWords.begin(), goodWords.end());
	int n = reviews.size();
	pair<int, int> goodness[n];
	vector<string> output(n);
	for (int i = 0; i < n; i++) {
		string review = reviews[i];
		int m = review.length();
		int numGoodWords = 0;
		int s = 0;
		for (int j = 0; j < m; j++) {
			if (review[j] == ' ') {
				if (words.find(review.substr(s, j - s)) != words.end()) {
					numGoodWords++;
				}
				s = j + 1;
			}
		}
		if (words.find(review.substr(s)) != words.end()) {
			numGoodWords++;
		}
		pair<int, int> goodnessi = {numGoodWords, i};
		goodness[i] = goodnessi;
	}
	sort(goodness, goodness + n, [&] (pair<int, int> &p1, pair<int, int> &p2) {
		if(p1.first < p2.first) {
			return p1.first < p2.first;
		}
		else {
			if(p1.first == p2.first) {
				return p1.second >= p2.second;
			}
			else {
				return p1.first < p2.first;
			}
		}
	});
	reverse(goodness, goodness + n);
	for (int i = 0; i < n; i++) {
		output[i] = reviews[goodness[i].second];
	}
	return output;
}
Java

class GoodnessComparator implements Comparator<int[]> {
    public int compare(int[] a, int[] b) {
		if (a[0] < b[0]) {
			return 1;
		}
		if (a[0] == b[0]) {
			if (a[1] < b[1]) {
				return -1;
			} else {
				return 1;
			}
		}
		return -1;
    }
}
class Solution {
	String[] orderReviews(String[] reviews, String[] goodWords) {
	    // add your logic here
		Set<String> words = new HashSet<>(Arrays.asList(goodWords));
		int n = reviews.length;

		int[][] goodness = new int[n][2];
		String[] output = new String[n];
		for (int i = 0; i < n; i++) {
			String review = reviews[i];
			int m = review.length();
			int numGoodWords = 0;
			int s = 0;
			for (int j = 0; j < m; j++) {
				if (review.charAt(j) == ' ') {
					if (words.contains(review.substring(s, j))) {
						numGoodWords++;
					}
					s = j + 1;
				}
			}
			if (words.contains(review.substring(s))) {
				numGoodWords++;
			}
			int[] goodnessi = {numGoodWords, i};
			goodness[i] = goodnessi;
		}
		Arrays.sort(goodness, new GoodnessComparator());
		for (int i = 0; i < n; i++) {
			output[i] = reviews[goodness[i][1]];
		}
		return output;
	}
}

Alternative Approach

Alternatively, we can use Trie to solve this problem. We can construct a Trie on the Good Words, and by traversing on our Trie, we can check if the review string has some good word in it and keep its count. Finally we sort the result using a custom comparator, and return the output.

Analysis

  • Time Complexity: O(n * |word length|)
  • Space Complexity: O(n)

Implementation

C++
class TrieNode {
private:
    TrieNode* children[26];
    bool isEnd = false;
public:
    bool hasWord(string w) {
        TrieNode* nextNode = this;
        for (int i = 0; i < w.size(); i++) {
            nextNode = nextNode->children[w[i] - 'a'];
            if (!nextNode) {
                return false;
            }
            if (i == w.size() - 1) {
                return nextNode->isEnd;
            }
        }
        return false;
    }
    void addWord(string w) {
        TrieNode* nextNode = this;
        for (int i = 0; i < w.size(); i++) {
            int nextIndex = w[i] - 'a';
            if (!nextNode->children[nextIndex]) {
                nextNode->children[nextIndex] = new TrieNode();
            }
            nextNode = nextNode->children[nextIndex];
            if (i == w.size() - 1) {
                nextNode->isEnd = true;
                return;
            }
        }
    }
};

bool compPairDesc(const pair<int,int> &a, const pair<int,int> &b) {
    if (a.first > b.first) {
		return true;
	}
	if (a.first == b.first && a.second < b.second) {
		return true;
	}
	return false;
}

vector<string> orderReviews(vector<string> &reviews, vector<string> &goodWords) {
    vector<string> output(reviews.size());
    TrieNode* root = new TrieNode();
    for (int i = 0; i < goodWords.size(); i++) {
        root->addWord(goodWords[i]);
    }
    vector<pair<int, int>> goodness;
    for (int i = 0; i < reviews.size(); i++) {
        string review = reviews[i];
        int numGoodWords = 0;
        int s = 0;
        for (int j = 0; j < review.size(); j++) {
            if (review[j] == ' ') {
                if (root->hasWord(review.substr(s, j - s))) {
                    numGoodWords++;
                }
                s = j + 1;
            }
        }
        if (root->hasWord(review.substr(s, review.size() - s))) {
            numGoodWords++;
        }
        goodness.push_back(make_pair(numGoodWords, i));
    }
    sort(goodness.begin(), goodness.end(), compPairDesc);
    for (int i = 0; i < reviews.size(); i++) {
        output[i] = reviews[goodness[i].second];
    }
    return output;
}
Java
class Solution {
	class Pair {
		int first, second;
		Pair(int first, int second) {
			this.first = first;
			this.second = second;
		}
	}
	class TrieNode {
		TrieNode[] children = new TrieNode[26];
		boolean isEnd = false;
		public boolean hasWord(String w) {
			TrieNode nextNode = this;
			for (int i = 0; i < w.length(); i++) {
				nextNode = nextNode.children[w.charAt(i) - 'a'];
				if (nextNode == null) {
					return false;
				}
				if (i == w.length() - 1) {
					return nextNode.isEnd;
				}
			}
			return false;
		}
		public void addWord(String w) {
			TrieNode nextNode = this;
			for (int i = 0; i < w.length(); i++) {
				int nextIndex = w.charAt(i) - 'a';
				if (nextNode.children[nextIndex] == null) {
					nextNode.children[nextIndex] = new TrieNode();
				}
				nextNode = nextNode.children[nextIndex];
				if (i == w.length() - 1) {
					nextNode.isEnd = true;
					return;
				}
			}
		}
	}

	String[] orderReviews(String[] reviews, String[] goodWords) {
		String[] output = new String[reviews.length];
		TrieNode root = new TrieNode();
		for (int i = 0; i < goodWords.length; i++) {
			root.addWord(goodWords[i]);
		}
		Pair[] goodness = new Pair[reviews.length];
		int goodnessIndx = 0;
		for (int i = 0; i < reviews.length; i++) {
			String review = reviews[i];
			int numGoodWords = 0;
			int s = 0;
			for (int j = 0; j < review.length(); j++) {
				if (review.charAt(j) == ' ') {
					if (root.hasWord(review.substring(s, j))) {
						numGoodWords++;
					}
					s = j + 1;
				}
			}
			if (root.hasWord(review.substring(s, review.length()))) {
				numGoodWords++;
			}
			goodness[goodnessIndx++] = (new Pair(numGoodWords, i));
		}
		Arrays.sort(goodness, new Comparator<Pair> () {
			public int compare(Pair a, Pair b) {
				if(a.first < b.first) {
					return 1;
				}
				if(a.first == b.first && a.second > b.second) {
					return 1;
				}
				return - 1;
			}
		});
		for (int i = 0; i < reviews.length; i++) {
			output[i] = reviews[goodness[i].second];
		}
		return output;
	}
}
Related Content
Shortest Unique Prefix
SDE Bootcamp - Become a software engineer at a product-based company
Practice Data Structures & Algorithms
Learning Resources
Interview Prep Resources
Community
Join our community
Blog
  • Career Advice and Roadmaps
  • Data Structures & Algorithms
  • Machine Coding Round (LLD)
  • System Design & Architecture
  • Backend Development
  • Frontend Development
  • Awesome Project Ideas
  • Core Computer Science
Practice Questions
  • Machine Coding (LLD) Questions
  • System Design (HLD) Questions
  • Topic-wise DSA Questions
  • Company-wise DSA Questions
  • DSA Sheets (Curated Lists)
  • JavaScript Interview Questions
  • Frontend UI Machine Coding Questions
Online Compilers (IDE)
  • Online Java Compiler
  • Online C++ Compiler
  • Online C Compiler
  • Online Python Compiler
  • Online JavaScript Compiler
Topic-wise Problems
  • Dynamic Programming Interview Questions
  • Linked List Interview Questions
  • Graph Interview Questions
  • Backtracking Interview Questions
  • Arrays Interview Questions
  • Trees Interview Questions
Company-wise Problems
  • Amazon Interview Questions
  • Microsoft Interview Questions
  • Google Interview Questions
  • Flipkart Interview Questions
  • Adobe Interview Questions
  • Facebook Interview Questions
DSA Sheets (Curated Lists)
  • Top Interview Questions
  • FAANG Interview Questions
  • Most Asked Interview Questions
  • 6 month DSA Practice Sheet
  • 3 month DSA Practice Sheet
  • Last minute DSA Practice Sheet