[Community Puzzle] 1D Spreadsheet

Thank’s i finished it :slight_smile:

The concept of Memoization in Javascript is backed by two main sub-concepts: Closure and High order function. In JavaScript, closures are generated every time a function is created and it allows you access to the domain of the outer function from the inner function. A high order function accepts another function as an argument or returns a function as its output.

This technique is specially useful when it comes to dynamic programming . A memoized function is usually faster because if the function is called subsequently with the previous value(s), then instead of executing the function, would be fetching the result from the cache .

Usage

function test(a) {
  console.log('calling test', a);
  return a + 1;
}

const memoized = memoize(test);

memoized(1); // prints calling test and returns 2
memoized(1); // returns 2
memoized(2); // prints calling test and returns 3

Bonjour,

mon code réussi tout les tests mais quand je le soumet, les Accounting is hard 1 & 2 ne passent.
Quelqu’un peut m’aider?

Oh my god… It took me at least 4 hours to solve this task. It was so complicated for me. Now I am afraid to start exercises at the medium level.
Well, I just want to wish good luck to everyone who is struggling with this puzzle.

Don’t be afraid, it’s a hard puzzle for an easy one.

Hi guys,

I’ve been testing a lot of things related to memoization to solve this puzzle but I don’t see where I should store the computed values. I’ve read in this forum that it sould be done “on the way back” and I kind of get what it means but not fully :-).

It would be great if anyone could give me a hint on where and how I should implement this.
Thanks !

(I know my code is a bit messy but I’d like to iplement the memoization before refactoring)

const N = parseInt(readline())
const cells = []

    // Storing the sheet
    for (let i = 0; i < N; i++) {
        const cell = {}
        const input = readline().split(' ')
        cell.operation = input[0]
        cell.arg1 = input[1]
        cell.arg2 = input[2]
        cells.push(cell)
    }

    function resolve(cell) {
        switch (cell.operation) {
            case "VALUE" :
                return evaluate(cell.arg1)
            case "ADD" :
                return evaluate(cell.arg1) + evaluate(cell.arg2)
            case "SUB" :
                return evaluate(cell.arg1) - evaluate(cell.arg2)
            case "MULT" :
                return evaluate(cell.arg1) * evaluate(cell.arg2)
        }
    }

    function evaluate(arg) {
        // Argument is a reference
        if (isNaN(arg)) {
            let ref = Number(arg.split("").slice(1,).join(""))
            return resolve(cells[ref])
        }
        else return Number(arg)
    }

    // Output
    for (cell of cells) {
        cell.value = resolve(cell)
        console.log(cell.value)
    }

Take test case 9 as an example, your first few function calls are:

resolve $1 4
evaluate $1
resolve 3 _
evaluate 3
evaluate 4
resolve 3 _
evaluate 3

And later on “resolve 3 _” and “evaluate 3” appear 3 more times, “resolve $1 4” etc appears one more time. If instead, you have stored the values you have calculated in your “cell”, you can retrieve those values directly when they are needed later. That way you can make fewer function calls and avoid evaluating over and over again.

Hope this will help you think about how you may implement memoization!

1 Like

Thanks for the tip, I think I understand a bit more now but I still don’t see how I can implement it :slight_smile: .

I’ll do some research hoping it will clik for me !

Thank you.

1 Like

Well it clicked, thanks for the good explanation, it really helped and now I pass all the tests :partying_face:.

1 Like

Thanks for feedback. Event-driven solution is elegant for this puzzle.

1 Like

Hi ! Nice problem, which I solved using some sort of dependency graph. Not a short code base, no memoization nor recursion, but elegant and (I hope) time and memory efficient. Also, using Rust, this leads to writing nested enums and lots of matches, interesting!

One comment: tests “Accounting is hard 1” and 2: they are the only ones to use “VALUE $n”, and because they are long and deep, I had a hard time circumventing the issue.

So, in case this is not on purpose, I suggest adding a test case, with much less items but all kinds of references :slight_smile:

1 Like

Hello guys,
got a strange problem from test12, i’ve passed all the test except this one.
Was wondering if there is a problem in javascript with “e+” big number notation?

here’s my first 10 outputs:(0 expected on first output)

3.2660158100154436e+42
41183844
3.2660158100154436e+42
-6840
-351206151180
-1.594610959505992e+23
-6246
-6840
0
2280

Please walk through your code to see how you got those numbers, and compare your outputs against the expected outputs (you get the full list by clicking the button left of PLAY ALL TESTCASES and then test 12).

Thanks, it helped.
got a bad condition which involved multiplication by zero not to work.
I could suggest testing * 0 in test 4

tbh it could be on average puzzle, specially for the last 3 tests, good exercice tho

Hi
did nt do on purpose but my first reflex was to use a simple iterative approach in C#
no recursion and no associated memoization and it works i guess ok

maybe a little comment on this since other people had to fight hard to limit depth of the stack with recursion.

1 Like

Hi guys,

I tried to resolve this puzzle since last week in C++, but I am unable to get the tests 11 & 12 validated.

I don’t understand why, but for example in the test 11, one “reference” don’t resolve at all, and my code try to convert a “$2” to an int, which make the program to crash …

Here is my code :

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Cell
{
    public:
    bool isResolved{false};
    string arg1{}, arg2{}, operation{}, result{};

    void print()
    {
        cerr << "arg1:" << arg1 << "\narg2:" << arg2 << "\nop:" 
            << operation << "\nisResolved:" << isResolved << "\nresult:" << result << "\n" << std::endl;
    }
};

bool makeCellOperation(Cell& cell, vector<Cell>& cells);

string resolveRef(const string& ref, vector<Cell>& cells)
{
    int index{stoi(ref.substr(1))};

    if (!(cells[index].isResolved))
    {
        makeCellOperation(cells[index], cells);    
    }
    return (cells[index].result);
}

void checkRef(Cell& cell, vector<Cell>& cells)
{
    cerr << "Before:\n";
    cerr << '\t' << cell.arg1 << "\n\t" << cell.arg2 << '\n';

    if (cell.arg1[0] == '$' || cell.arg1[0] == 36)
        cell.arg1 = resolveRef(cell.arg1, cells);
    
    if (cell.arg2[0] == '$' || cell.arg1[0] == 36)
        cell.arg2 = resolveRef(cell.arg2, cells);

    cerr << "After:\n";
    cerr << '\t' << cell.arg1 << "\n\t" << cell.arg2 << '\n';
}

bool makeCellOperation(Cell& cell, vector<Cell>& cells)
{

    if (cell.operation == "VALUE")
    {
        cell.result = cell.arg1;
        cell.isResolved = true;
        return cell.isResolved;
    }
    else if (cell.operation == "ADD")
    {
        checkRef(cell, cells);

        cell.result = to_string(stoi(cell.arg1) + stoi(cell.arg2));
        cell.isResolved = true;
        return cell.isResolved;
    }
    else if (cell.operation == "SUB")
    {
        checkRef(cell, cells);

        if (cell.arg2 == "-81")
        {
            if (cell.arg1[0] == '$')
                cerr << "DOLLARS\n";
            cerr << static_cast<int>(cell.arg1[0]);
        }
       
        cell.result = to_string(stoi(cell.arg1) - stoi(cell.arg2));
        cell.isResolved = true;
        return cell.isResolved;
    }
    else
    {
        checkRef(cell, cells);
        
        cell.result = to_string(stoi(cell.arg1) * stoi(cell.arg2));
        cell.isResolved = true;
        return cell.isResolved;
    }
}

bool resolveCells(vector<Cell>& cells)
{
    bool isResolved{true};

    for (Cell& c : cells)
    {
        if (!(c.isResolved))
            makeCellOperation(c, cells);
    }

    return isResolved;
}

int main()
{
    int n;
    cin >> n; cin.ignore();
    
    vector<Cell> cells{};
    for (int i = 0; i < n; i++) {
        Cell cell{};
        
        cin >> cell.operation >> cell.arg1 >> cell.arg2; cin.ignore();
        cells.push_back(cell);
    }

    for (Cell c : cells)
    {
        resolveCells(cells);      
    }

    for (Cell c : cells)
    {
        cout << c.result << std::endl;
    }
}

And the output on test 11:

Aborted.

at abort.c. function __GI_abort () on line 79

at string_conversions.h. function __gnu_cxx::__stoa<long, int, char, int> (__convf=0x7ffff7bd1ef0 <__strtol>, __name=0x555555559004 "stoi", __str=0x5555555742b8 "$2", __idx=0x0) on line 83

at basic_string.h. function std::__cxx11::stoi (__str="$2", __idx=0x0, __base=10) on line 6620

at Answer.cpp. function makeCellOperation (cell=..., cells=std::vector of length 100, capacity 128 = {...}) on line 77

at Answer.cpp. function resolveCells (cells=std::vector of length 100, capacity 128 = {...}) on line 98

at Answer.cpp. function main () on line 119

### Sortie standard :

Before:

$47

$9

Before:

$4

$74

Before:

$57

$67

Before:

$93

$54

Before:

$27

$59

Before:

$59

$67

Before:

993

-871

After:

993

-871

Before:

3

$59

After:

3

122

After:

122

-119

After:

3

122

Before:

$67

$1

Before:

44

$59

After:

44

122

After:

-119

-78

After:

125

-41

After:

166

-119

Before:

$96

$25

Before:

$59

$6

Before:

$59

$59

After:

122

122

After:

122

244

Before:

$6

$6

After:

244

244

After:

366

0

After:

285

366

After:

$2

-81

DOLLARS

36terminate called after throwing an instance of 'std::invalid_argument'

what(): stoi

### Échec

Trouvé :

Rien

Attendu :

-119

Anyone to help me ? What is wrong with my code ? :frowning:

It looks like this part of the code does not handle the case of “VALUE $x _” correctly. Similar expressions are not tested in test cases 1 to 10, where the argument after “VALUE” is always an integer instead of a reference.

    if (cell.operation == "VALUE")
    {
        cell.result = cell.arg1;
        cell.isResolved = true;
        return cell.isResolved;
    }

2 Likes

Oh god, I feel stupid. I didn’t realized that when the operation is a “VALUE”, the value of arg_1 can be a reference.

I will try to fix that to see if it works.

Thank you very much for your answer @5DN1L :slight_smile:

2 Likes

description should be clearer. In the example window the example should go few level deeper, otherwise one can interpret description in many ways.

Very good puzzle. Really had to work on some recursive programming.
HOWEVER. I do think this belongs in the medium or hard puzzle.

2 Likes