Skip to content

Commit

Permalink
Add algorithms for 2Sum, 3Sum, Kadane's Algorithm, and linked list pr…
Browse files Browse the repository at this point in the history
…oblems
  • Loading branch information
karankumar12345 committed Oct 6, 2024
1 parent 18da83a commit 08d2300
Show file tree
Hide file tree
Showing 10 changed files with 400 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Data-Structures/Array/2Sum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// twoSum.js

/**
*
* Time Complexity: O(n) — We traverse the list once while storing elements in a hash map.
Space Complexity: O(n) — In the worst case, we store all elements in the hash map.
* Finds indices of the two numbers such that they add up to a specific target.
* @param {number[]} nums - An array of numbers.
* @param {number} target - The target sum.
* @returns {number[]|null} - Indices of the two numbers or null if not found.
*/
export function twoSum(nums, target) {
const map = new Map();

for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement), i];
}
map.set(nums[i], i);
}

return null; // No two sum solution
}
41 changes: 41 additions & 0 deletions Data-Structures/Array/3sum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// threeSum.js

/**
* Time Complexity: O(n^2) — The outer loop runs in O(n), and the inner two-pointer approach runs in O(n).
Space Complexity: O(1) — The output list is the only extra space used (not counting input).
*
*
* Finds all unique triplets in the array that sum up to zero.
* @param {number[]} nums - An array of numbers.
* @returns {number[][]} - A list of unique triplets.
*/
export function threeSum(nums) {
const result = [];
nums.sort((a, b) => a - b); // Sort the array

for (let i = 0; i < nums.length - 2; i++) {
// Skip duplicate values
if (i > 0 && nums[i] === nums[i - 1]) continue;

let left = i + 1;
let right = nums.length - 1;

while (left < right) {
const sum = nums[i] + nums[left] + nums[right];

if (sum === 0) {
result.push([nums[i], nums[left], nums[right]]);
while (left < right && nums[left] === nums[left + 1]) left++; // Skip duplicates
while (left < right && nums[right] === nums[right - 1]) right--; // Skip duplicates
left++;
right--;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}

return result; // Return the list of triplets
}
25 changes: 25 additions & 0 deletions Data-Structures/Array/KandanesAlgo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

// kadanesAlgorithm.js

/**
*
*
* Time Complexity: O(n) — The algorithm processes each element of the array once.
Space Complexity: O(1) — Only a constant amount of additional space is used.
* Finds the maximum sum of a contiguous subarray using Kadane's Algorithm.
* @param {number[]} nums - An array of numbers.
* @returns {number} - The maximum sum of the contiguous subarray.
*/
export function maxSubArray(nums) {
let maxSoFar = nums[0];
let maxEndingHere = nums[0];

for (let i = 1; i < nums.length; i++) {
maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
maxSoFar = Math.max(maxSoFar, maxEndingHere);
}

return maxSoFar; // Return the maximum sum
}
34 changes: 34 additions & 0 deletions Data-Structures/Array/test/2sum.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// test.js

import { twoSum } from '../2Sum';



function testTwoSum() {
// Test Case 1: Basic case
let nums = [2, 7, 11, 15];
let target = 9;
let result = twoSum(nums, target);
console.assert(JSON.stringify(result) === JSON.stringify([0, 1]), `Expected [0, 1], got ${result}`);

// Test Case 2: No solution
nums = [1, 2, 3];
target = 6;
result = twoSum(nums, target);
console.assert(result === null, `Expected null, got ${result}`);

// Test Case 3: Duplicate values
nums = [3, 2, 4];
target = 6;
result = twoSum(nums, target);
console.assert(JSON.stringify(result) === JSON.stringify([1, 2]), `Expected [1, 2], got ${result}`);

// Test Case 4: Negative numbers
nums = [-3, 4, 3, 90];
target = 0;
result = twoSum(nums, target);
console.assert(JSON.stringify(result) === JSON.stringify([0, 2]), `Expected [0, 2], got ${result}`);

console.log("All 2-Sum tests passed!");
}
testTwoSum();
30 changes: 30 additions & 0 deletions Data-Structures/Array/test/3sum.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// test.js


import { threeSum } from '../3sum';
function testThreeSum() {
// Test Case 1: Basic case
let nums = [-1, 0, 1, 2, -1, -4];
let result = threeSum(nums);
console.assert(JSON.stringify(result) === JSON.stringify([[-1, -1, 2], [-1, 0, 1]]), `Expected [[-1, -1, 2], [-1, 0, 1]], got ${JSON.stringify(result)}`);

// Test Case 2: No triplet
nums = [1, 2, 3];
result = threeSum(nums);
console.assert(JSON.stringify(result) === JSON.stringify([]), `Expected [], got ${JSON.stringify(result)}`);

// Test Case 3: Duplicate triplets
nums = [-2, 0, 0, 2, 2];
result = threeSum(nums);
console.assert(JSON.stringify(result) === JSON.stringify([[-2, 0, 2]]), `Expected [[-2, 0, 2]], got ${JSON.stringify(result)}`);

// Test Case 4: All negative numbers
nums = [-1, -2, -3, -4];
result = threeSum(nums);
console.assert(JSON.stringify(result) === JSON.stringify([]), `Expected [], got ${JSON.stringify(result)}`);

console.log("All 3-Sum tests passed!");
}

// Run the tests
testThreeSum();
35 changes: 35 additions & 0 deletions Data-Structures/Array/test/KadanesAlgo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// testKadanesAlgorithm.js

import { maxSubArray } from '../KandanesAlgo.js';

function runKadaneTests() {
// Test Case 1: Basic case
let nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4];
let result = maxSubArray(nums);
console.assert(result === 6, `Expected 6, got ${result}`);

// Test Case 2: All negative numbers
nums = [-1, -2, -3, -4];
result = maxSubArray(nums);
console.assert(result === -1, `Expected -1, got ${result}`);

// Test Case 3: All positive numbers
nums = [1, 2, 3, 4];
result = maxSubArray(nums);
console.assert(result === 10, `Expected 10, got ${result}`);

// Test Case 4: Mixed numbers with zero
nums = [0, -1, 2, 3, -2, 5, -3];
result = maxSubArray(nums);
console.assert(result === 8, `Expected 8, got ${result}`);

// Test Case 5: Single element
nums = [-5];
result = maxSubArray(nums);
console.assert(result === -5, `Expected -5, got ${result}`);

console.log("All Kadane's Algorithm tests passed!");
}

// Run the tests
runKadaneTests();
39 changes: 39 additions & 0 deletions Data-Structures/Linked-List/FindIntersectionPoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@


/**
* Calculates the intersection point of two lines
* defined by the points (x1, y1) to (x2, y2) and (x3, y3) to (x4, y4).
*
* @param {number} x1 - x-coordinate of the first point of the first line
* @param {number} y1 - y-coordinate of the first point of the first line
* @param {number} x2 - x-coordinate of the second point of the first line
* @param {number} y2 - y-coordinate of the second point of the first line
* @param {number} x3 - x-coordinate of the first point of the second line
* @param {number} y3 - y-coordinate of the first point of the second line
* @param {number} x4 - x-coordinate of the second point of the second line
* @param {number} y4 - y-coordinate of the second point of the second line
* @returns {Object|null} The intersection point { x, y } or null if no intersection
*/

export function findIntersection(x1, y1, x2, y2, x3, y3, x4, y4) {
const denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

// Lines are parallel if denom is zero
if (denom === 0) {
return null; // No intersection
}

const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom;
const ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom;

// Check if intersection is within the segments
if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
return null; // Intersection not within the segments
}

// Calculate the intersection point
const intersectionX = x1 + ua * (x2 - x1);
const intersectionY = y1 + ua * (y2 - y1);

return { x: intersectionX, y: intersectionY };
}
77 changes: 77 additions & 0 deletions Data-Structures/Linked-List/SlowFast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// slowFast.js

// Definition for singly-linked list node
class ListNode {
constructor(value) {
this.value = value;
this.next = null;
}
}

/**
* Detects if a linked list has a cycle.
* @param {ListNode} head - The head of the linked list.
* @returns {boolean} - True if there's a cycle, false otherwise.
*/
export function hasCycle(head) {
let slow = head;
let fast = head;

while (fast && fast.next) {
slow = slow.next; // Move slow pointer one step
fast = fast.next.next; // Move fast pointer two steps

if (slow === fast) {
return true; // Cycle detected
}
}
return false; // No cycle
}

/**
* Finds the middle element of a linked list.
* @param {ListNode} head - The head of the linked list.
* @returns {ListNode|null} - The middle node or null if the list is empty.
*/
export function findMiddle(head) {
if (!head) return null;

let slow = head;
let fast = head;

while (fast && fast.next) {
slow = slow.next; // Move slow pointer one step
fast = fast.next.next; // Move fast pointer two steps
}
return slow; // Slow pointer is at the middle
}

/**
* Detects the start of the cycle in a linked list.
* @param {ListNode} head - The head of the linked list.
* @returns {ListNode|null} - The node where the cycle starts or null if there is no cycle.
*/
export function detectCycle(head) {
let slow = head;
let fast = head;

// First phase: determine if a cycle exists
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;

if (slow === fast) {
// Cycle detected
let entry = head;
while (entry !== slow) {
entry = entry.next; // Move entry pointer
slow = slow.next; // Move slow pointer
}
return entry; // Start of the cycle
}
}
return null; // No cycle
}

// Exporting the ListNode class for testing
export { ListNode };
44 changes: 44 additions & 0 deletions Data-Structures/Linked-List/test/FindIntersectionpoint.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

import { findIntersection } from '../FindIntersectionPoint';

function runTests() {
const tests = [
{
desc: 'Intersecting lines',
input: [0, 0, 2, 2, 0, 2, 2, 0],
expected: { x: 1, y: 1 }
},
{
desc: 'Parallel lines (no intersection)',
input: [0, 0, 2, 2, 0, 1, 2, 3],
expected: null
},
{
desc: 'Overlap lines (fully overlapping)',
input: [0, 0, 2, 2, 1, 1, 3, 3],
expected: { x: 1, y: 1 }
},
{
desc: 'Non-intersecting lines (far apart)',
input: [0, 0, 1, 1, 2, 2, 3, 3],
expected: null
},
{
desc: 'Intersecting at an endpoint',
input: [0, 0, 2, 2, 2, 0, 0, 2],
expected: { x: 2, y: 2 }
}
];

tests.forEach(({ desc, input, expected }, index) => {
const result = findIntersection(...input);
const isPassed = JSON.stringify(result) === JSON.stringify(expected);
console.log(`Test ${index + 1}: ${desc} - ${isPassed ? 'Passed' : 'Failed'}`);
if (!isPassed) {
console.log(` Expected: ${JSON.stringify(expected)}, Got: ${JSON.stringify(result)}`);
}
});
}

// Run the tests
runTests();
Loading

0 comments on commit 08d2300

Please sign in to comment.