Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/problem4/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
.git
.gitignore
README.md
Dockerfile
.dockerignore
2 changes: 2 additions & 0 deletions src/problem4/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# dependencies (bun install)
node_modules
12 changes: 12 additions & 0 deletions src/problem4/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM oven/bun:1.3.11-alpine

WORKDIR /app

COPY package.json bun.lock ./
RUN bun install --frozen-lockfile

COPY tsconfig.json ./
COPY sum.ts ./
COPY tests ./tests

CMD ["bun", "test"]
29 changes: 29 additions & 0 deletions src/problem4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# problem4

Three implementations of `sum_to_n` (formula, recursion, loop) with complexity analysis.

## Assumptions

The solution is presented under these assumptions:

- **Negative Integers:** for all negative integers, their absolute values must be taken.

- **NaN & Infinity:** all inputs are validated against `NaN` or `Infinity` and should return `0` for these.

## Run Tests with Docker

Build the image:

```bash
docker build -t problem4 ./src/problem4
```

Run the test suite:

```bash
docker run -t --rm problem4
```

The container uses [Bun](https://bun.com) and executes `bun test` by default.

This project was created using `bun init` in bun v1.3.11.
26 changes: 26 additions & 0 deletions src/problem4/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions src/problem4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "problem4",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
}
}
80 changes: 80 additions & 0 deletions src/problem4/sum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const sameSum = [0, 1];

const isValidInput = (
n: number
): boolean =>
Number.isInteger(n) && n >= 0;

const normalizeInput = (
n: number
): number =>
Math.abs(Math.trunc(n));

/**
* Base Gateway (Higher-Order Function)
* Wraps a core logic function with validation and normalization.
*/
const base_gateway = (
coreFormula: (n: number) => number
): ((n: number) => number) => {
return (n: number): number => {
const normalized = normalizeInput(n);

if (!isValidInput(normalized)) {
// If invalid, safely return the base case (0) without re-invoking the gateway
return 0;
}

if (sameSum.includes(n)) {
// If 0, 1, the sum, output, will be the same as input
return n;
}

// Pass the cleaned, normalized input to the actual formula
return coreFormula(normalized);
};
};

const formula = (n: number): number => (n * (n + 1)) / 2;

const looping = (n: number): number => {
let sum = 0;
for (let i = n; i > 0; i--) {
sum += i;
}
return sum;
}

const recursion = (n: number): number => {
if (n <= 0) return 0;
return n + recursion(n - 1);
}

/**
* **Implementation A: Carl Friedrich Gauss's Arithmetic Progression**
*
* **Complexity Analysis**
* - **Time Complexity:** O(1) (Constant Time) — Executes a fixed number of
* arithmetic operations (one addition, one multiplication, one division)
* - **Space Complexity:** O(1) (Constant Space) — No additional memory or
* variables are allocated.
*/
export const sum_to_n_a = base_gateway(formula);

/**
* **Implementation B: The Recursive Approach**
*
* **Complexity Analysis:**
* - **Time Complexity:** O(n) (Linear Time). The function calls itself n times before hitting the base case.
* - **Space Complexity:** O(n) (Linear Space). Each recursive call adds a new frame to the call stack.
*/
export const sum_to_n_b = base_gateway(recursion);

/**
* **Implementation C: The Iterative Loop**
*
* **Complexity Analysis:**
* - **Time Complexity:** O(n) (Linear Time). The loop runs exactly n times, so the execution time scales linearly with the size of n.
* - **Space Complexity:** O(1) (Constant Space). It only requires a single variable (sum) to track the running total, occupying minimal, fixed memory.
*/
export const sum_to_n_c = base_gateway(looping);
81 changes: 81 additions & 0 deletions src/problem4/tests/sum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { describe, it, expect } from "bun:test";
import { sum_to_n_a, sum_to_n_b, sum_to_n_c } from "../sum";

// A helper array to easily run the same test cases across all three implementations
const implementations = [
{
name: "Implementation A (Formula)",
fn: sum_to_n_a,
testRecursiveLimit: false,
},
{
name: "Implementation B (Recursive)",
fn: sum_to_n_b,
testRecursiveLimit: true,
},
{
name: "Implementation C (Loop)",
fn: sum_to_n_c,
testRecursiveLimit: false,
},
];

implementations.forEach(({ name, fn, testRecursiveLimit }) => {
describe(`sum_to_n - ${name}`, () => {
// 1. Standard Happy Path Tests
describe("Standard inputs", () => {
it("should correctly sum up to 1", () => {
expect(fn(1)).toBe(1);
});

it("should correctly sum up to 5 (1+2+3+4+5)", () => {
expect(fn(5)).toBe(15);
});

it("should correctly sum up to 10", () => {
expect(fn(10)).toBe(55);
});

it("should correctly sum up to 100", () => {
expect(fn(100)).toBe(5050);
});
});

// 2. Edge Cases (Zero and Negative Numbers)
describe("Edge cases", () => {
it("should return 0 when n is 0", () => {
expect(fn(0)).toBe(0);
});

it("should normalize negative integers and correctly sum up to 15", () => {
expect(fn(-5)).toBe(15);
});
});

// 3. Large Inputs & Precision Boundary Tests
describe("Large inputs and safety boundaries", () => {
it("should accurately sum to a moderately large number (n = 200,000)", () => {
// If it's the recursive function, it will throw a stack overflow here.
// We handle this expected architectural limitation gracefully in the test.
if (testRecursiveLimit) {
expect(() => fn(200000)).toThrow(RangeError);
} else {
expect(fn(200000)).toBe(20000100000);
}
});

// This test checks the boundary condition mentioned in your prompt
it("should accurately result in a value just under MAX_SAFE_INTEGER", () => {
if (!testRecursiveLimit) {
// For n = 134,217,726, the sum is 9,007,199,122,864,127
// This is less than MAX_SAFE_INTEGER (9,007,199,254,740,991)
const n = 134217726;
const expectedSum = (n * (n + 1)) / 2;

expect(fn(n)).toBe(expectedSum);
expect(fn(n)).toBeLessThan(Number.MAX_SAFE_INTEGER);
}
});
});
});
});
30 changes: 30 additions & 0 deletions src/problem4/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
"types": ["bun-types"],

// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,

// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,

// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}
9 changes: 9 additions & 0 deletions src/problem5/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
data
*.db
*.db-journal
*.db-wal
*.db-shm
.git
.gitignore
README.md
6 changes: 6 additions & 0 deletions src/problem5/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
PORT=8000
HOST=0.0.0.0
DB_PATH=./data/app.db
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=200
IDEMPOTENCY_TTL_MS=86400000
6 changes: 6 additions & 0 deletions src/problem5/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
data/*.db
data/*.db-journal
data/*.db-wal
data/*.db-shm
.env
18 changes: 18 additions & 0 deletions src/problem5/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM oven/bun:1.3.11-alpine

WORKDIR /app

COPY package.json bun.lock* ./
RUN bun install --frozen-lockfile || bun install

COPY tsconfig.json ./
COPY src ./src

RUN mkdir -p /app/data
ENV DB_PATH=/app/data/app.db
ENV PORT=8000
ENV HOST=0.0.0.0

EXPOSE 8000

CMD ["bun", "run", "src/index.ts"]
15 changes: 15 additions & 0 deletions src/problem5/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM oven/bun:1.3.11-alpine

WORKDIR /app

COPY package.json bun.lock* ./
RUN bun install --frozen-lockfile || bun install

COPY tsconfig.json bunfig.toml ./
COPY src ./src
COPY tests ./tests

ENV NODE_ENV=test
ENV CI=true

CMD ["bun", "test"]
Loading