Why is my Grid Traveler Memoization still sticking? - c++11

I'm currently working on implementing memoization into the Grid Traveler problem. It looks like it should work, but it's still sticking on bigger cases like (18,18). Did I miss something, or are maps not the right choice for this kind of problem?
P.S. I'm still very new at working with maps.
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
uint64_t gridTravMemo(int m, int n, unordered_map<string, uint64_t>grid)
{
string key;
key = to_string(m) + "," + to_string(n);
if (grid.count(key) > 0)
return grid.at(key);
if (m == 1 && n == 1)
return 1;
if (m == 0 || n == 0)
return 0;
grid[key] = gridTravMemo(m-1, n, grid) + gridTravMemo(m, n-1, grid);
return grid.at(key);
}
int main()
{
unordered_map<string, uint64_t> gridMap;
cout << gridTravMemo(1, 1, gridMap) << endl;
cout << gridTravMemo(2, 2, gridMap) << endl;
cout << gridTravMemo(3, 2, gridMap) << endl;
cout << gridTravMemo(3, 3, gridMap) << endl;
cout << gridTravMemo(18, 18, gridMap) << endl;
return 0;
}

The point of memorized search is to optimize running time by returning any previous values that you have calculated. This way, instead of a brute force algorithm, you can reach a runtime of O(N*M).
However, you are passing your unordered_map<string, uint64_t>grid as a parameter for your depth-first search.
You are calling grid[key] = gridTravMemo(m-1, n, grid) + gridTravMemo(m, n-1, grid); This means that your search is splitting into two branches. However, the grid in these two branches are different. This means that the same state can be visited in two separate branches, leading to a runtime more like O(2^(N*M)).
When you're testing an 18x18 grid, this definitely will not run quickly enough.
This is relatively easy to fix. Just declare grid as a global variable. This way its values can be used between different branches.
Try something like this:
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
unordered_map<string, uint64_t> grid;
uint64_t gridTravMemo(int m, int n)
{
string key;
key = to_string(m) + "," + to_string(n);
if (grid.count(key) > 0)
return grid.at(key);
if (m == 1 && n == 1)
return 1;
if (m == 0 || n == 0)
return 0;
grid[key] = gridTravMemo(m-1, n) + gridTravMemo(m, n-1);
return grid.at(key);
}
int main()
{
cout << gridTravMemo(1, 1) << endl;
grid.clear()
cout << gridTravMemo(2, 2) << endl;
grid.clear()
cout << gridTravMemo(3, 2) << endl;
grid.clear()
cout << gridTravMemo(3, 3) << endl;
grid.clear()
cout << gridTravMemo(18, 18) << endl;
return 0;
}

Related

Recursive function doesn't return the vector<int> list correctly

I'm trying to create a list which contains 10 unique random numbers between 1 and 20 by using a recursive function. Here is the code.
Compiler: GNU g++ 10.2.0 on Windows
Compiler flags: -DDEBUG=9 -ansi -pedantic -Wall -std=c++11
#include <iostream>
#include <vector>
#include <algorithm>
#include <time.h>
using namespace std;
vector<int> random (int size, int range, int randnum, vector<int> randlist ) {
if (size < 1) {
cout << "returning...(size=" << size << ")" << endl;
return randlist;
}
else {
if (any_of(randlist.begin(), randlist.end(),[randnum](int elt) {return randnum == elt;})){
cout << "repeating number: " << randnum << endl;
random(size, range, rand() % range + 1, randlist);
return randlist;
}
else {
cout << "size " << size << " randnum " << randnum << endl;
randlist.push_back(randnum);
random(size-1, range, rand() % range + 1, randlist);
return randlist; }
}
}
int main (int argc, char *argv[]) {
srand (time(NULL));
vector<int> dummy{};
vector<int> uniqrandnums = random(10, 20, (rand() % 20) + 1, dummy );
cout << "here is my unique random numbers list: " ;
for_each(uniqrandnums.begin(),uniqrandnums.end(), [](int n){cout << n << ' ';});
}
To keep track of the unique random numbers, I've added 2 cout lines inside the recursive function random. The recursive function seems to operate correctly but it can't return back the resulting vector<int list randlist correctly; it seems to return a list with just the first random number it found.
Note: Reckoning that the function would finally return from here:
if (size < 1) {
cout << "returning...(size=" << size << ")" << endl;
return randlist;
}
I haven't initially added the last 2 return randlist; lines inside the recursive function but as is, it gave compilation warning control reaches end of non-void function [-Wreturn-type] That's why I've added those 2 return statements but it made just the warnings go away and it didn't help operate correctly.
Question: How to arrange the code so the recursive function random returns the full list in a correct manner?
The issue is that you are discarding the result of recursive calls to randlist(). In the two places where you call:
random(..., randlist);
return randlist;
Replace that with:
return random(..., randlist);

How can we add element to map<int,int>... so that they are stored in non increasing order in map

How can I make std::map<int,int> sorting values in non increasing order ?
map<int,int> mp;
mp[5]=7; // {5->7}
mp[3]=9; // {5->7,3->9}
mp[4]=9; // {5->7,4->9,3->9}
#include <iostream>
#include <map>
int main()
{
std::map<int, int, std::greater<int>> mp;
mp[5] = 7;
mp[3] = 9;
mp[4] = 9;
for (auto [k, v] : mp)
{
std::cout << "\n" << k << "->" << v;
}
return 0;
}
Which prints:
5->7
4->9
3->9
We used std::greater<int> instead of default std::lesser<int> see std::map
Also please note that you can also iterate over reverse order using a reverse_iterator (the rbegin()/rend() methods):
auto iter = mp.rbegin();
const auto iter_end = mp.rend();
while (iter != iter_end)
{
std::cout << "\n" << iter->first << "->" << iter->second;
++iter;
}
will print map (key,value) in the reversed order...
3->9
4->9
5->7

How do a find the maximum non-repeating number in an integer array?

Suppose I have an unsorted integer array {3, -1, 4, 5, -3, 2, 5}, and I want to find the maximum non-repeating number (4 in this case) (5 being invalid as it is repeated). How can I achieve this?
Use an unordered map to count the frequencies of each element. (As an optimization, keep track of largest element encountered and skip elements lower than that.) Then, scan the map to find out the largest element with frequency exactly equal to 1.
template <typename T> // numeric T
pair<T, bool> FindMaxNonRepeating(vector<T> const& vec) {
unordered_map<T, int> elem2freq;
for (auto const& elem : vec) {
elem2freq[elem] += 1;
}
T largest_non_repetitive = std::numeric_limits<T>::min();
bool found = false;
for (auto const& item : elem2freq) {
if (item.first > largest_non_repetitive && item.second == 1) {
largest_non_repetitive = item.first;
found = true;
}
}
return {largest_non_repetitive, found};
}
This runs in time complexity O(n) and requires space complexity O(n).
Sort the array in descending order.
Begin from top element and store it a variable, say max.
Check next element with max, if they are the same, repeat until
you find the next max, otherwise, you found the max non-repeated
number.
Time complexity: O(nlogn)
c++ implementation, based on my Sort (C++):
#include <algorithm>
#include <iostream>
#include <vector>
#include <limits>
#include <cstddef>
using namespace std;
void printVector(vector<int>& v)
{
for(vector<int>::iterator it = v.begin() ; it != v.end() ; it++)
cout << *it << ' ';
cout << endl;
}
bool compar(const int& a, const int& b)
{
return (a > b) ? true : false;
}
int main()
{
vector<int> v = {3, -1, 4, 5, -3, 2, 5};
cout << "Before sorting : " << endl;
printVector(v);
sort(v.begin(), v.end(), compar);
cout << endl << "After sorting : " << endl;
printVector(v);
int max_non_repeat = numeric_limits<int>::min();
for(unsigned int i = 0; i < v.size(); ++i)
{
if(max_non_repeat == v[i])
max_non_repeat = numeric_limits<int>::min();
else if(v[i] > max_non_repeat)
max_non_repeat = v[i];
}
cout << "Max non-repeated element: " << max_non_repeat << endl;
return 0;
}
Output:
C02QT2UBFVH6-lm:~ gsamaras$ g++ -Wall -std=c++0x main.cpp
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out
Before sorting :
3 -1 4 5 -3 2 5
After sorting :
5 5 4 3 2 -1 -3
Max non-repeated element: 4
For maximum pleasure, do base your (a different) approach on How to find max. and min. in array using minimum comparisons? and modify it accordingly.

I want to use a random number to generate one of two cout's randomly

I am trying to use a number randomly selected between 1 and 2 and use that to display a random cout. I can't quite get this to work. Any suggestions? Thanks!
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
srand(time(0));
for (int i = 1; i <= 1; i++)
{
int d1 = rand() % 2 + 1;
cout << d1 << endl;
cout << endl;
system("pause");
if (d1 == "1");
{
cout << "hello";
}
if (d1 == "2")
{
cout << "goodbye";
}
return 0;
}
First i recommend you make sure that you are not comparing an int to a string. Also remove the semicolon from after the first if statement.
if (d1 == 1)
{
cout << "hello";
}
Next make an else if statement instead of a new if statement.
else if (d1 == 2)
{
cout << "goodbye";
}
This should fix just about everything. Hope this helps. Goobyebye!
You're comparing an int to a string. change to, e.g. d1 == 1
That should get you going...
Compare the int to an int, then use the else clause.
Also, your if statement doesn't need a semicolon.
if (d1 == 1)
{
cout << "hello";
}
else
{
cout << "goodbye";
}
When you make a statement like:
if (d1 == "1")
You are comparing a string and an integer. Try:
if(d1 == 1)

find chars/string in string from vector c++

I have a vector of strings, and I want to count all 'Ace' in the vector. Right now I can only find one...
int main()
{
std::vector<string> vec;
vec.push_back("Ace of Spades");
vec.push_back("Ace");
string value = "Ace";
int cnt = 0;
auto iter = find_if(begin(vec), end(vec), [&](const string &str)
{
return str.find(value) != str.npos;
});
if(iter == end(vec))
cout << "no found" << endl;
else
{
cout << *iter << endl;
cnt++;
cout << cnt++ << endl;
}
}
You could use std::count_if:
auto cnt = count_if(begin(vec),
end(vec),
[&](const string& str) {
return str.find(value) != std::string::npos;
});
Note that this only counts the number of strings containing "Ace", not the total number of occurrences of "Ace" in the vector's elements.
If you just want to count the number of matching elements, you could use std::count_if.
If you also need to do something with them, it would probably be best to forget about the standard library algorithms and use a ranged for like so:
int count = 0;
for (const auto& element : vec) {
if (element.find(value) != std::string::npos) {
std::cout << element << std::endl;
++count;
}
}
std::cout << count << std::endl;

Resources