Comparisons of strings with c++ - c++

I used to have some code in C++ which stores strings as a series of characters in a character matrix (a string is a row). The classes Character matrix and LogicalVector are provided by Rcpp.h:
LogicalVector unq_mat( CharacterMatrix x ){
int nc = x.ncol() ; // Get the number of columns in the matrix.
LogicalVector out(nc); // Make a logical (bool) vector of the same length.
// For every col in the matrix, assess whether the column contains more than one unique character.
for( int i=0; i < nc; i++ ) {
out[i] = unique( x(_,i) ).size() != 1 ;
}
return out;
}
The logical vector identifies which columns contain more than one unique character. This is then passed back to the R language and used to manipulate a matrix. This is a very R way of thinking of doing this. However I'm interested in developing my thinking in C++, I'd like to write something that achieves the above: So finds out which characters in n strings are not all the same, but preferably using the stl classes like std::string. As a conceptual example given three strings:
A = "Hello", B = "Heleo", C = "Hidey". The code would point out that positions/characters 2,3,4,5 are not one value, but position/character 1 (the 'H') is the same in all strings (i.e. there is only one unique value). I have something below that I thought worked:
std::vector<int> StringsCompare(std::vector<string>& stringVector) {
std::vector<int> informative;
for (int i = 0; i < stringVector[0].size()-1; i++) {
for (int n = 1; n < stringVector.size()-1; n++) {
if (stringVector[n][i] != stringVector[n-1][i]) {
informative.push_back(i);
break;
}
}
}
return informative;
}
It's supposed to go through every character position (0 to size of string-1) with the outer loop, and with the inner loop, see if the character in string n is not the same as the character in string n-1. In cases where the character is all the same, for example the H in my hello example above, this will never be true. For cases where the characters in the strings are different the inter loops if statement will be satisfied, the character position recorded, and the inner loop broken out of. I then get a vector out containing the indicies of the characters in the n strings where the characters are not all identical. However these two functions give me different answers. How else can I go through n strings char by char and check they are not all identical?
Thanks,
Ben.

I expected #doctorlove to provide an answer. I'll enter one here in case he does not.
To iterate through all of the elements of a string or vector by index, you want i from 0 to size()-1. for (int i=0; i<str.size(); i++) stops just short of size, i.e., stops at size()-1. So remove the -1's.
Second, C++ arrays are 0-based, so you must adjust (by adding 1 to the value that is pushed into the vector).
std::vector<int> StringsCompare(std::vector<std::string>& stringVector) {
std::vector<int> informative;
for (int i = 0; i < stringVector[0].size(); i++) {
for (int n = 1; n < stringVector.size(); n++) {
if (stringVector[n][i] != stringVector[n-1][i]) {
informative.push_back(i+1);
break;
}
}
}
return informative;
}
A few things to note about this code:
The function should take a const reference to vector, as the input vector is not modified. Not really a problem here, but for various reasons, it's a good idea to declare unmodified input references as const.
This assumes that all the strings are at least as long as the first. If that doesn't hold, the behavior of the code is undefined. For "production" code, you should include a check for the length prior to extracting the ith element of each string.

Related

Given an integer K and a matrix of size t x t. construct a string s consisting of first t lowercase english letters such that the total cost of s is K

I'm solving this problem and stuck halfway through, looking for help and a better method to tackle such a problem:
problem:
Given an integer K and a matrix of size t x t. we have to construct a string s consisting of the first t lowercase English letters such that the total cost of s is exactly K. it is guaranteed that there exists at least one string that satisfies given conditions. Among all possible string s which is lexicographically smallest.
Specifically the cost of having the ith character followed by jth character of the English alphabet is equal to cost[i][j].
For example, the cost of having 'a' followed by 'a' is denoted by cost[0][0] and the cost of having 'b' followed by 'c' is denoted by cost[1][3].
The total cost of a string is the total cost of two consecutive characters in s. for matrix cost is
[1 2]
[3 4],
and the string is "abba", then we have
the cost of having 'a' followed by 'b' is is cost[0][1]=2.
the cost of having 'b' followed by 'b' is is `cost0=4.
the cost of having 'b' followed by 'a' is cost0=3.
In total, the cost of the string "abba" is 2+4+3=9.
Example:
consider, for example, K is 3,t is 2, the cost matrix is
[2 1]
[3 4]
There are two strings that its total cost is 3. Those strings are:
"aab"
"ba"
our answer will be "aab" as it is lexicographically smallest.
my approach
I tried to find and store all those combinations of i, j such that it sums up to desired value k or is individual equals k.
for above example
v={
{2,1},
{3,4}
}
k = 3
and v[0][0] + v[0][1] = 3 & v[1][0] = 3 . I tried to store the pairs in an array like this std::vector<std::vector<std::pair<int, int>>>. and based on it i will create all possible strings and will store in the set and it will give me the strings in lexicographical order.
i stucked by writing this much code:
#include<iostream>
#include<vector>
int main(){
using namespace std;
vector<vector<int>>v={{2,1},{3,4}};
vector<pair<int,int>>k;
int size=v.size();
for(size_t i=0;i<size;i++){
for(size_t j=0;j<size;j++){
if(v[i][j]==3){
k.push_back(make_pair(i,j));
}
}
}
}
please help me how such a problem can be tackled, Thank you. My code can only find the individual [i,j] pairs that can be equal to desired K. I don't have idea to collect multiple [i,j] pairs which sum's to desired value and it also appears my approach is totally naive and based on brute force. Looking for better perception to solve the problems and implement it in the code. Thank you.
This is a backtracking problem. General approach is :
a) Start with the "smallest" letter for e.g. 'a' and then recurse on all the available letters. If you find a string that sums to K then you have the answer because that will be the lexicographically smallest as we are finding it from smallest to largest letter.
b) If not found in 'a' move to the next letter.
Recurse/backtrack can be done as:
Start with a letter and the original value of K
explore for every j = 0 to t and reducing K by cost[i][j]
if K == 0 you found your string.
if K < 0 then that path is not possible, so remove the last letter in the string, try other paths.
Pseudocode :
string find_smallest() {
for (int i = 0; i < t; i++) {
s = (char)(i+97)
bool value = recurse(i,t,K,s)
if ( value ) return s;
s = ""
}
return ""
}
bool recurse(int i, int t, int K, string s) {
if ( K < 0 ) {
return false;
}
if ( K == 0 ) {
return true;
}
for ( int j = 0; j < t; j++ ) {
s += (char)(j+97);
bool v = recurse(j, t, K-cost[i][j], s);
if ( v ) return true;
s -= (char)(j+97);
}
return false;
}
In your implementation, you would probably need another vector of vectors of pairs to explore all your candidates. Also another vector for updating the current cost of each candidate as it builds up. Following this approach, things start to get a bit messy (IMO).
A more clean and understandable option (IMO again) could be to approach the problem with recursivity:
#include <iostream>
#include <vector>
#define K 3
using namespace std;
string exploreCandidate(int currentCost, string currentString, vector<vector<int>> &v)
{
if (currentCost == K)
return currentString;
int size = v.size();
int lastChar = (int)currentString.back() - 97; // get ASCII code
for (size_t j = 0; j < size; j++)
{
int nextTotalCost = currentCost + v[lastChar][j];
if (nextTotalCost > K)
continue;
string nextString = currentString + (char)(97 + j); // get ASCII char
string exploredString = exploreCandidate(nextTotalCost, nextString, v);
if (exploredString != "00") // It is a valid path
return exploredString;
}
return "00";
}
int main()
{
vector<vector<int>> v = {{2, 1}, {3, 4}};
int size = v.size();
string initialString = "00"; // reserve first two positions
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
initialString[0] = (char)(97 + i);
initialString[1] = (char)(97 + j);
string exploredString = exploreCandidate(v[i][j], initialString, v);
if (exploredString != "00") { // It is a valid path
cout << exploredString << endl;
return 0;
}
}
}
}
Let us begin from the main function:
We define our matrix and iterate over it. For each position, we define the corresponding sequence. Notice that we can use indices to get the respective character of the English alphabet, knowing that in ASCII code a=97, b=98...
Having this initial sequence, we can explore candidates recursively, which lead us to the exploreCandidate recursive function.
First, we want to make sure that the current cost is not the value we are looking for. If it is, we leave immediately without even evaluating the following iterations for candidates. We want to do this because we are looking for the lexicographically smallest element, and we are not asked to provide information about all the candidates.
If the cost condition is not satisfied (cost < K), we need to continue exploring our candidate, but not for the whole matrix but only for the row corresponding to the last character. Then we can encounter two scenarios:
The cost condition is met (cost = K): if at some point of recursivity the cost is equal to our value K, then the string is a valid one, and since it will be the first one we encounter, we want to return it and finish the execution.
The cost is not valid (cost > K): If the current cost is greater than K, then we need to abort this branch and see if other branches are luckier. Returning a boolean would be nice, but since we want to output a string (or maybe not, depending on the statement), an option could be to return a string and use "00" as our "false" value, allowing us to know whether the cost condition has been met. Other options could be returning a boolean and using an output parameter (passed by reference) to contain the output string.
EDIT:
The provided code assumes positive non-zero costs. If some costs were to be zero you could encounter infinite recursivity, so you would need to add more constraints in your recursive function.

Finding the most(multiple) common word in C++ using unordered_map approach

Find the most common word from a text input, excluding a list of given words. If there are multiple maximum words, display all of them.
My method words for 21/24 test cases, I cannot seem to think of the 3 test cases that I am missing.
I am adding the code that I have right now, which is efficient according to me. I don't want another way of implementing it right now (although suggestions are most welcome), I would just like to pick your brain about the possible test cases I am missing.
vector<string> mostCommonWord(string paragraph, vector<string>& banned) {
unordered_map<string, int>m;
for(int i = 0; i < paragraph.size();){
string s = "";
while(i < paragraph.size() && isalpha(paragraph[i])) s.push_back(tolower(paragraph[i++])); // go through till you find one word completely
while(i < paragraph.size() && !isalpha(paragraph[i])) i++; // avoid all the white spaces and other characters
m[s]++; // include the word found and increment its count
}
for(auto x: banned) m[x] = 0; // make the count of all the banned words to be 0
vector<string> result;
string res = "";
int count = INT_MIN;
// find the maximum count
for(auto x: m)
if(x.second > count) count = x.second;
// we might have the case where all the words were in banned words, which would result the count == -1, so return an empty vector in this case
if(count <= 0) return result;
// add the words corresponding to that to the final vector<string>
for(auto x: m)
if(x.second == count) result.push_back(x.first);
return result;
}
It works for all the scenarios I can think, but fails 3 test cases.
I am not given access to those test cases, would just like to have a discussion of what it could possibly be!
Are you sure in the fact that other chars (digits) should be treated as word delimiters?
If paragraph starts with a whitespace or not an alphabetical char you will insert the empty string into the map: m[""] = 1.

Why does the longest prefix which is also suffix calculation part in the KMP have a time complexity of O(n) and not O(n^2)?

I was going through the code of KMP when I noticed the Longest Prefix which is also suffix calculation part of KMP. Here is how it goes,
void computeLPSArray(char* pat, int M, int* lps)
{
int len = 0;
lps[0] = 0;
int i = 1;
while (i < M) {
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1]; //<----I am referring to this part
}
else
{
lps[i] = 0;
i++;
}
}
}
}
Now the part where I got confused was the one which I have shown in comments in the above code. Now we do know that when a code contains a loop like the following
int a[m];
memset(a, 0, sizeof(a));
for(int i = 0; i<m; i++){
for(int j = i; j>=0; j--){
a[j] = a[j]*2;//This inner loop is causing the same cells in the 1
//dimensional array to be visited more than once.
}
}
The complexity comes out to be O(m*m).
Similarly if we write the above LPS computation in the following format
while(i<M){
if{....}
else{
if(len != 0){
//doesn't this part cause the code to again go back a few elements
//in the LPS array the same way as the inner loop in my above
//written nested for loop does? Shouldn't that mean the same cell
//in the array is getting visited more than once and hence the
//complexity should increase to O(M^2)?
}
}
}
It might be that the way I think complexities are calculated is wrong. So please clarify.
If expressions do not take time that grows with len.
Len is an integer. Reading it takes O(1) time.
Array indexing is O(1).
Visiting something more than once does not mean you are higher O notation wise. Only if the visit count grows faster than kn for some k.
If you carefully analyze the algorithm of creating prefix table, you may notice that the total number of rollbacked positions could be m at most, so the upper bound for total number of iterations is 2*m which yields O(m)
Value of len grows alongside the main iterator i and whenever there is a mismatch, len drops back to zero value but this "drop" cannot exceed the interval passed by the main iterator i since the start of match.
For example, let's say, the main iterator i started matching with len at position 5 and mismatched at position 20.
So,
LPS[5]=1
LPS[6]=2
...
LPS[19]=15
At the moment of mismatch, len has a value of 15. Hence it may rollback at most 15 positions down to zero, which is equivalent to the interval passed by i while matching. In other words, on every mismatch, len travels back no more than i has traveled forward since the start of match

C++: First non-repeating character, O(n) time using hash map

I'm trying to write a function to get the first non-repeating character of a string. I haven't found a satisfactory answer on how to do this in O(n) time for all cases. My current solution is:
char getFirstNonRepeated(char * str) {
if (strlen(str) > 0) {
int visitedArray[256] = {}; // Where 256 is the size of the alphabet
for (int i = 0; i < strlen(str); i++) {
visitedArray[str[i]] += 1;
}
for (int j = 0; j < 256; j++) {
if (visitedArray[j] == 1) return j;
}
}
return '\0'; // Either strlen == 0 or all characters are repeated
}
However, as long as n < 256, this algorithm runs in O(n^2) time in the worst case. I've read that using a hash table instead of an array to store the number of times each character is visited could get the algorithm to run consistently in O(n) time, because insertions, deletions, and searches on hash tables run in O(1) time. I haven't found a question that explains how to do this properly. I don't have very much experience using hash maps in C++ so any help would be appreciated.
Why are you repeating those calls to strlen() in every loop? That is linear with the length of the string, so your first loop effectively becomes O(n^2) for no good reason at all. Just calculate the length once and store it, or use str[i] as the end condition.
You should also be aware that if your compiler uses signed characters, any character value above 127 will be considered negative (and used as a negative, i.e. out of bounds, array offset). You can avoid this by explicitly casting your character values to be unsigned char.

How to access elements in vectors in Lists more efficiently?

I have a problem where I want to combine a list of vectors, all of the same type, in a particular fashion. I want the first element of my resultant vector to be the first element of the first vector in my list, the second element should be the first element of the second vector, the third, the first of the third and so on until n where n is length of my list and then element n+1 should be the second element of the first vector. This repeats until finished.
Currently, I am doing it like this:
CharacterVector measure(nrows * expansion);
CharacterVector temp(nrows);
for(int i=0; i < measure.size(); i++){
temp = values[i % expansion];
measure[i] = temp[i / expansion];
}
return(measure);
Where values is the List of CharacterVectors. This seems incredibly inefficient, overwriting temp every single time but I don't know of a better way to access the elements in values. I don't know a lot of C++ but I assume there must be a better way.
Any and all help is greatly appreciate!
EDIT:
All vectors in 'values are of the same length nrows and values has expansion elements in it.
What you need is the ListOf<CharacterVector> class. As the name implies, it represents an R list which only contains CharacterVector.
The code below uses it to extract the second element of each character vector from the list. Should not be hard to adapt it to your expansion algorithm, but your example was not reproducible without a bit more context.
#include <Rcpp.h>
using namespace Rcpp ;
// [[Rcpp::export]]
CharacterVector second( ListOf<CharacterVector> values ){
int n = values.size() ;
CharacterVector res(n);
for(int i=0; i<n; i++){
res[i] = values[i][1] ;
}
return res ;
}
Then, you sourceCpp this and try it on some sample data:
> data <- list(letters, letters, LETTERS)
> second(data)
[1] "b" "b" "B"
Now about your assumption:
This seems incredibly inefficient, overwriting temp every single time
Creating a CharacterVector is pretty fast, there is no deep copy of data, so this should not have been an issue in the first place.
You can preconstruct the vector and can easily know at which positions the elements of the first vector should go.. i.e. measure[0], measure[n], measure[n*2] etc.. where n = mylist.size(). Here i assume of course that each vector in the list has equal size. Untested code:
CharacterVector measure(nrows * expansion);
for(int i=0; i < values.size(); ++i)
{
CharacterVector& temp = values[i];
int newPosition = i;
for( int j=0; j < temp.size(); ++j)
{
measure[newPosition ] = temp[j];
newPosition += expansion;
}
}
return(measure);