: add_space_to_make_sentence.cpp
This commit is contained in:
136
puzzles/training/add_space_to_make_sentence.cpp
Normal file
136
puzzles/training/add_space_to_make_sentence.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
VIM: let b:cf5build="clang++ -std=c++20 -O2 -pthread -I. {SRC} -o {OUT}"
|
||||
VIM: let b:cf5run="{OUT}"
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
## Problem Description
|
||||
|
||||
Given an input of a dictionary of words and an input string that does not
|
||||
contain spaces, write a method that returns a string with spaces inserted
|
||||
accordingly.
|
||||
|
||||
## Expected Completion Time
|
||||
|
||||
For unoptimized recursive solution: 25 minutes
|
||||
|
||||
## Problem Complexity Level
|
||||
|
||||
Coding Fluency: Medium
|
||||
|
||||
Problem Solving: Medium
|
||||
|
||||
## Questions the candidate might ask
|
||||
|
||||
1) Do you need to find all combinations of sentences? Always return
|
||||
the sentence with the shorter valid matches.
|
||||
2) What if there are spaces already in the string? Assume there aren't
|
||||
already spaces.
|
||||
3) What are the valid set of characters (eg. uppercase, symbols)? Assume
|
||||
dictionary is always all lowercase and are letters.
|
||||
4) What happens if nothing matches in the dictionary? Return null/none.
|
||||
5) What if there are left over characters in the string? Return null/none.
|
||||
|
||||
## Sample inputs - Expected outputs
|
||||
|
||||
Input: "bloombergisfun", ["bloom","bloomberg","is","fun"]
|
||||
Output: "bloomberg is fun"
|
||||
|
||||
## Input corner cases
|
||||
|
||||
Input: "bloombergisfun", ["bloom", "bloomberg","is"]
|
||||
Output: None/Null
|
||||
|
||||
Input: "bloombergisfun", ["bloom", "berg", "bloomberg","is","fun"]
|
||||
Output: "bloom berg is fun"
|
||||
|
||||
## Runtime complexity
|
||||
|
||||
Recursive Solution: O(2^N)
|
||||
This solution O(N*K) where `K` is max length of word in vocab)
|
||||
|
||||
Note:
|
||||
hashing of a string is not an O(1) function, but O(N) therefore complexity
|
||||
is O(N*K^2). But it can be made O(N*K).
|
||||
|
||||
*/
|
||||
|
||||
using dict_t = std::unordered_set<std::string>;
|
||||
|
||||
std::string solution(const std::string& str, const dict_t& dict)
|
||||
{
|
||||
size_t minw = str.size() +1;
|
||||
size_t maxw = 0;
|
||||
for (const auto& w : dict){
|
||||
minw = std::min(minw, w.size());
|
||||
maxw = std::max(maxw, w.size());
|
||||
}
|
||||
|
||||
std::vector<std::string> memo(str.size()+1, std::string());
|
||||
|
||||
for (size_t i = 0; i < str.size(); ++i){
|
||||
if (i != 0 && memo[i].empty()){
|
||||
continue;
|
||||
}
|
||||
for (size_t j = minw; j <= maxw && i+j <= str.size(); ++j){
|
||||
std::string candidate(str.data()+i, j);
|
||||
auto it = dict.find(candidate);
|
||||
if (it != dict.end()){
|
||||
memo[i+j]=memo[i] + " " + *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return memo[str.size()];
|
||||
}
|
||||
|
||||
void test(const std::string& str, const dict_t& dict)
|
||||
{
|
||||
std::cout << "dict=[";
|
||||
bool first = true;
|
||||
for (const auto& word : dict){
|
||||
if (first){
|
||||
first = false;
|
||||
} else {
|
||||
std::cout <<", ";
|
||||
}
|
||||
std::cout << word;
|
||||
}
|
||||
std::cout << "]\n";
|
||||
std::cout << "str='" << str << "' -> ";
|
||||
std::cout.flush();
|
||||
std::cout << "'" << solution(str, dict) << "'\n\n";
|
||||
}
|
||||
|
||||
int main ( void )
|
||||
{try{
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
test("bloombergisfun", {"bloom","bloomberg","is","fun"});
|
||||
test("bloombergisfun", {"bloom","bloomberg","is"});
|
||||
test("bloombergisfun", {"bloom", "berg", "bloomberg","is","fun"});
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> seconds = end - begin;
|
||||
std::cout << "Time: " << seconds.count() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
std::cerr << std::endl
|
||||
<< "std::exception(\"" << e.what() << "\")." << std::endl;
|
||||
return 2;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
std::cerr << std::endl
|
||||
<< "unknown exception." << std::endl;
|
||||
return 1;
|
||||
}}
|
||||
Reference in New Issue
Block a user