Skip to content

Commit 08d2300

Browse files
Add algorithms for 2Sum, 3Sum, Kadane's Algorithm, and linked list problems
1 parent 18da83a commit 08d2300

10 files changed

+400
-0
lines changed

Data-Structures/Array/2Sum.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// twoSum.js
2+
3+
/**
4+
*
5+
* Time Complexity: O(n) — We traverse the list once while storing elements in a hash map.
6+
Space Complexity: O(n) — In the worst case, we store all elements in the hash map.
7+
8+
9+
* Finds indices of the two numbers such that they add up to a specific target.
10+
* @param {number[]} nums - An array of numbers.
11+
* @param {number} target - The target sum.
12+
* @returns {number[]|null} - Indices of the two numbers or null if not found.
13+
*/
14+
export function twoSum(nums, target) {
15+
const map = new Map();
16+
17+
for (let i = 0; i < nums.length; i++) {
18+
const complement = target - nums[i];
19+
if (map.has(complement)) {
20+
return [map.get(complement), i];
21+
}
22+
map.set(nums[i], i);
23+
}
24+
25+
return null; // No two sum solution
26+
}

Data-Structures/Array/3sum.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// threeSum.js
2+
3+
/**
4+
* Time Complexity: O(n^2) — The outer loop runs in O(n), and the inner two-pointer approach runs in O(n).
5+
Space Complexity: O(1) — The output list is the only extra space used (not counting input).
6+
*
7+
*
8+
* Finds all unique triplets in the array that sum up to zero.
9+
* @param {number[]} nums - An array of numbers.
10+
* @returns {number[][]} - A list of unique triplets.
11+
*/
12+
export function threeSum(nums) {
13+
const result = [];
14+
nums.sort((a, b) => a - b); // Sort the array
15+
16+
for (let i = 0; i < nums.length - 2; i++) {
17+
// Skip duplicate values
18+
if (i > 0 && nums[i] === nums[i - 1]) continue;
19+
20+
let left = i + 1;
21+
let right = nums.length - 1;
22+
23+
while (left < right) {
24+
const sum = nums[i] + nums[left] + nums[right];
25+
26+
if (sum === 0) {
27+
result.push([nums[i], nums[left], nums[right]]);
28+
while (left < right && nums[left] === nums[left + 1]) left++; // Skip duplicates
29+
while (left < right && nums[right] === nums[right - 1]) right--; // Skip duplicates
30+
left++;
31+
right--;
32+
} else if (sum < 0) {
33+
left++;
34+
} else {
35+
right--;
36+
}
37+
}
38+
}
39+
40+
return result; // Return the list of triplets
41+
}

Data-Structures/Array/KandanesAlgo.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
// kadanesAlgorithm.js
3+
4+
/**
5+
*
6+
*
7+
* Time Complexity: O(n) — The algorithm processes each element of the array once.
8+
Space Complexity: O(1) — Only a constant amount of additional space is used.
9+
10+
11+
* Finds the maximum sum of a contiguous subarray using Kadane's Algorithm.
12+
* @param {number[]} nums - An array of numbers.
13+
* @returns {number} - The maximum sum of the contiguous subarray.
14+
*/
15+
export function maxSubArray(nums) {
16+
let maxSoFar = nums[0];
17+
let maxEndingHere = nums[0];
18+
19+
for (let i = 1; i < nums.length; i++) {
20+
maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
21+
maxSoFar = Math.max(maxSoFar, maxEndingHere);
22+
}
23+
24+
return maxSoFar; // Return the maximum sum
25+
}
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// test.js
2+
3+
import { twoSum } from '../2Sum';
4+
5+
6+
7+
function testTwoSum() {
8+
// Test Case 1: Basic case
9+
let nums = [2, 7, 11, 15];
10+
let target = 9;
11+
let result = twoSum(nums, target);
12+
console.assert(JSON.stringify(result) === JSON.stringify([0, 1]), `Expected [0, 1], got ${result}`);
13+
14+
// Test Case 2: No solution
15+
nums = [1, 2, 3];
16+
target = 6;
17+
result = twoSum(nums, target);
18+
console.assert(result === null, `Expected null, got ${result}`);
19+
20+
// Test Case 3: Duplicate values
21+
nums = [3, 2, 4];
22+
target = 6;
23+
result = twoSum(nums, target);
24+
console.assert(JSON.stringify(result) === JSON.stringify([1, 2]), `Expected [1, 2], got ${result}`);
25+
26+
// Test Case 4: Negative numbers
27+
nums = [-3, 4, 3, 90];
28+
target = 0;
29+
result = twoSum(nums, target);
30+
console.assert(JSON.stringify(result) === JSON.stringify([0, 2]), `Expected [0, 2], got ${result}`);
31+
32+
console.log("All 2-Sum tests passed!");
33+
}
34+
testTwoSum();
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// test.js
2+
3+
4+
import { threeSum } from '../3sum';
5+
function testThreeSum() {
6+
// Test Case 1: Basic case
7+
let nums = [-1, 0, 1, 2, -1, -4];
8+
let result = threeSum(nums);
9+
console.assert(JSON.stringify(result) === JSON.stringify([[-1, -1, 2], [-1, 0, 1]]), `Expected [[-1, -1, 2], [-1, 0, 1]], got ${JSON.stringify(result)}`);
10+
11+
// Test Case 2: No triplet
12+
nums = [1, 2, 3];
13+
result = threeSum(nums);
14+
console.assert(JSON.stringify(result) === JSON.stringify([]), `Expected [], got ${JSON.stringify(result)}`);
15+
16+
// Test Case 3: Duplicate triplets
17+
nums = [-2, 0, 0, 2, 2];
18+
result = threeSum(nums);
19+
console.assert(JSON.stringify(result) === JSON.stringify([[-2, 0, 2]]), `Expected [[-2, 0, 2]], got ${JSON.stringify(result)}`);
20+
21+
// Test Case 4: All negative numbers
22+
nums = [-1, -2, -3, -4];
23+
result = threeSum(nums);
24+
console.assert(JSON.stringify(result) === JSON.stringify([]), `Expected [], got ${JSON.stringify(result)}`);
25+
26+
console.log("All 3-Sum tests passed!");
27+
}
28+
29+
// Run the tests
30+
testThreeSum();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// testKadanesAlgorithm.js
2+
3+
import { maxSubArray } from '../KandanesAlgo.js';
4+
5+
function runKadaneTests() {
6+
// Test Case 1: Basic case
7+
let nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4];
8+
let result = maxSubArray(nums);
9+
console.assert(result === 6, `Expected 6, got ${result}`);
10+
11+
// Test Case 2: All negative numbers
12+
nums = [-1, -2, -3, -4];
13+
result = maxSubArray(nums);
14+
console.assert(result === -1, `Expected -1, got ${result}`);
15+
16+
// Test Case 3: All positive numbers
17+
nums = [1, 2, 3, 4];
18+
result = maxSubArray(nums);
19+
console.assert(result === 10, `Expected 10, got ${result}`);
20+
21+
// Test Case 4: Mixed numbers with zero
22+
nums = [0, -1, 2, 3, -2, 5, -3];
23+
result = maxSubArray(nums);
24+
console.assert(result === 8, `Expected 8, got ${result}`);
25+
26+
// Test Case 5: Single element
27+
nums = [-5];
28+
result = maxSubArray(nums);
29+
console.assert(result === -5, `Expected -5, got ${result}`);
30+
31+
console.log("All Kadane's Algorithm tests passed!");
32+
}
33+
34+
// Run the tests
35+
runKadaneTests();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
3+
/**
4+
* Calculates the intersection point of two lines
5+
* defined by the points (x1, y1) to (x2, y2) and (x3, y3) to (x4, y4).
6+
*
7+
* @param {number} x1 - x-coordinate of the first point of the first line
8+
* @param {number} y1 - y-coordinate of the first point of the first line
9+
* @param {number} x2 - x-coordinate of the second point of the first line
10+
* @param {number} y2 - y-coordinate of the second point of the first line
11+
* @param {number} x3 - x-coordinate of the first point of the second line
12+
* @param {number} y3 - y-coordinate of the first point of the second line
13+
* @param {number} x4 - x-coordinate of the second point of the second line
14+
* @param {number} y4 - y-coordinate of the second point of the second line
15+
* @returns {Object|null} The intersection point { x, y } or null if no intersection
16+
*/
17+
18+
export function findIntersection(x1, y1, x2, y2, x3, y3, x4, y4) {
19+
const denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
20+
21+
// Lines are parallel if denom is zero
22+
if (denom === 0) {
23+
return null; // No intersection
24+
}
25+
26+
const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom;
27+
const ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom;
28+
29+
// Check if intersection is within the segments
30+
if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
31+
return null; // Intersection not within the segments
32+
}
33+
34+
// Calculate the intersection point
35+
const intersectionX = x1 + ua * (x2 - x1);
36+
const intersectionY = y1 + ua * (y2 - y1);
37+
38+
return { x: intersectionX, y: intersectionY };
39+
}
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// slowFast.js
2+
3+
// Definition for singly-linked list node
4+
class ListNode {
5+
constructor(value) {
6+
this.value = value;
7+
this.next = null;
8+
}
9+
}
10+
11+
/**
12+
* Detects if a linked list has a cycle.
13+
* @param {ListNode} head - The head of the linked list.
14+
* @returns {boolean} - True if there's a cycle, false otherwise.
15+
*/
16+
export function hasCycle(head) {
17+
let slow = head;
18+
let fast = head;
19+
20+
while (fast && fast.next) {
21+
slow = slow.next; // Move slow pointer one step
22+
fast = fast.next.next; // Move fast pointer two steps
23+
24+
if (slow === fast) {
25+
return true; // Cycle detected
26+
}
27+
}
28+
return false; // No cycle
29+
}
30+
31+
/**
32+
* Finds the middle element of a linked list.
33+
* @param {ListNode} head - The head of the linked list.
34+
* @returns {ListNode|null} - The middle node or null if the list is empty.
35+
*/
36+
export function findMiddle(head) {
37+
if (!head) return null;
38+
39+
let slow = head;
40+
let fast = head;
41+
42+
while (fast && fast.next) {
43+
slow = slow.next; // Move slow pointer one step
44+
fast = fast.next.next; // Move fast pointer two steps
45+
}
46+
return slow; // Slow pointer is at the middle
47+
}
48+
49+
/**
50+
* Detects the start of the cycle in a linked list.
51+
* @param {ListNode} head - The head of the linked list.
52+
* @returns {ListNode|null} - The node where the cycle starts or null if there is no cycle.
53+
*/
54+
export function detectCycle(head) {
55+
let slow = head;
56+
let fast = head;
57+
58+
// First phase: determine if a cycle exists
59+
while (fast && fast.next) {
60+
slow = slow.next;
61+
fast = fast.next.next;
62+
63+
if (slow === fast) {
64+
// Cycle detected
65+
let entry = head;
66+
while (entry !== slow) {
67+
entry = entry.next; // Move entry pointer
68+
slow = slow.next; // Move slow pointer
69+
}
70+
return entry; // Start of the cycle
71+
}
72+
}
73+
return null; // No cycle
74+
}
75+
76+
// Exporting the ListNode class for testing
77+
export { ListNode };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
import { findIntersection } from '../FindIntersectionPoint';
3+
4+
function runTests() {
5+
const tests = [
6+
{
7+
desc: 'Intersecting lines',
8+
input: [0, 0, 2, 2, 0, 2, 2, 0],
9+
expected: { x: 1, y: 1 }
10+
},
11+
{
12+
desc: 'Parallel lines (no intersection)',
13+
input: [0, 0, 2, 2, 0, 1, 2, 3],
14+
expected: null
15+
},
16+
{
17+
desc: 'Overlap lines (fully overlapping)',
18+
input: [0, 0, 2, 2, 1, 1, 3, 3],
19+
expected: { x: 1, y: 1 }
20+
},
21+
{
22+
desc: 'Non-intersecting lines (far apart)',
23+
input: [0, 0, 1, 1, 2, 2, 3, 3],
24+
expected: null
25+
},
26+
{
27+
desc: 'Intersecting at an endpoint',
28+
input: [0, 0, 2, 2, 2, 0, 0, 2],
29+
expected: { x: 2, y: 2 }
30+
}
31+
];
32+
33+
tests.forEach(({ desc, input, expected }, index) => {
34+
const result = findIntersection(...input);
35+
const isPassed = JSON.stringify(result) === JSON.stringify(expected);
36+
console.log(`Test ${index + 1}: ${desc} - ${isPassed ? 'Passed' : 'Failed'}`);
37+
if (!isPassed) {
38+
console.log(` Expected: ${JSON.stringify(expected)}, Got: ${JSON.stringify(result)}`);
39+
}
40+
});
41+
}
42+
43+
// Run the tests
44+
runTests();

0 commit comments

Comments
 (0)