Skip to content

Latest commit

 

History

History
628 lines (508 loc) · 28.2 KB

03_Array Basics.md

File metadata and controls

628 lines (508 loc) · 28.2 KB

Arey bacho! Jaldi se class mein aa jao aur dhyan whiteboard par lagao.

Pichle chapter mein humne seekha ki Complexity Analysis kya hoti hai aur code ki performance ko scale par kaise evaluate kiya jata hai. Aaj hum DSA ke sabse pehle, sabse fundamental, aur real-world development mein sabse zyada use hone wale data structure ko disassemble karenge—Arrays!


1. WHAT IS AN ARRAY? (BASIC CONCEPT & MENTAL MODEL)

Array Kya Hai aur Kyun Chahiye?

Array ek linear data structure hai jo multiple values ko ek single variable ke under contiguous (ek ke baad ek consecutive) memory locations mein store karta hai.

Chalo ek real-life scenario socho. Manlo tum ek teacher ho aur tumhein apni class ke 5 students ke marks store karne hain.

  • Rasta 1: Tum 5 alag-alag variables banao: let marks1 = 97, let marks2 = 82, let marks3 = 76...
    • Problem: Agar tumhari class mein 1000 bacche ho gaye, toh kya tum 1000 variables manually declare karoge? Bilkul nahi! It will become a maintenance nightmare.
  • Rasta 2: Tum ek single container banao jise tum naam de do marks aur usme saare students ke marks ko ek consecutive line mein arrange kar do. Yahi container humara Array hai!
┌─────────────────────────────────────────────────────────────────────────┐
│                    ARRAY CONCEPTUAL MEMORY LAYOUT                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Index:       0       1       2       3       4                         │
│            ┌───────┬───────┬───────┬───────┬───────┐                    │
│  Value:    │  97   │  82   │  76   │  65   │  89   │                    │
│            └───────┴───────┴───────┴───────┴───────┘                    │
│  Address:   1000    1004    1008    1012    1016                        │
│             (Assuming each integer takes 4 bytes of memory)             │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Key Terms to Remember:

  1. Element: Array ke andar store hone wali har individual value ko hum element kehte hain (jaise 97 ya 82).
  2. Index: Array ke har ek box (compartment) ka ek numeric address hota hai, jise hum Index kehte hain. JavaScript mein index hamesha 0 se shuru hota hai (0-based indexing).
  3. Length: Array ke andar total kitne elements present hain, us count ko hum array ki length kehte hain (Is case mein length is 5).
  4. Base Address: Array ke sabse pehle element (index 0) ka jo memory address hota hai, use base address kehte hain (jaise upar diagram mein 1000).

Zero-Based Indexing ke Peeche ki Real Maths 🧠

Bohot se bache sochte hain, "Sir, counting 1 se kyun nahi shuru hoti?" Iske peeche ek simple pointer calculation hai.

Memory level par jab hum kisi element ka address nikalte hain, toh computer ek offset formula use karta hai: \[Address of Index i = Base Address + (i × Size of one element)\]

Chalo upar wale array se index 2 par rakhe element ka address nikalte hain: \[Address = 1000 + (2 × 4 bytes) = 1008\] Computer ko bina kisi loop ke directly memory address mil gaya! Kyunki pehle element ke liye offset 0 hai, isiliye index 0 se start hota hai taaki address direct Base Address ke barabar aaye: \[Address of Index 0 = 1000 + (0 × 4) = 1000\]


2. JAVASCRIPT ARRAYS vs TRADITIONAL ARRAYS

Interviews mein yeh question direct pucha jata hai. Dono ke beech ka conceptual difference dhyan se samajh lo:

Feature Traditional/Fixed Array (C++ / Java) JavaScript Array
Sizing Static length: Ek baar array declare kar diya (jaise size 5), toh memory lock ho jati hai. Use runtime par change nahi kar sakte. Dynamic length: Iska size runtime par dynamically grow ya shrink ho sakta hai.
Data Types Homogeneous: Saare elements ka data type exact same hona chahiye (e.g., pure integers). Heterogeneous: Ek hi array mein tum numbers, strings, booleans, nested arrays aur objects mix karke store kar sakte ho.
Memory Allocation Hamesha strictly Contiguous (continuous) blocks mein store hote hain. Engine level par iske do states hote hain: Packed ya Holey.

V8 Engine Mechanics under the Hood: Packed vs Holey Arrays ⚙️

V8 engine JavaScript arrays ko optimize karne ke liye unhe do layouts mein store karta hai:

  1. Packed Arrays (Contiguous): Agar tum array ko sequentially fill karte ho bina beech mein gaps chode (e.g. const arr =), toh engine ise contiguous block mein store karta hai. Is layout mein element access directly O(1) pointer arithmetic se hota hai aur performant hota hai.
  2. Holey Arrays (Sparse): Agar tum indices ko skip kar dete ho (e.g., index 0 par 10 set kiya aur directly index 100 par 90 set kiya), toh beech mein "holes" (undefined empty spaces) ban jate hain. Engine contiguous memory allocation chodh kar ise ek dictionary-like associative hash map mein convert kar deta hai. Isse element access slow ho jata hai kyunki engine ko prototype chain lookups perform karne padte hain.

3. CORE ARRAY OPERATIONS (Manual Implementations and Under-the-Hood Logic)

DSA mein strong hone ke liye, hum built-in methods ke piche ka raw manual logic seekhengay. Chalo har operation ko dhang se dekhte hain:

┌─────────────────────────────────────────────────────────────────────────┐
│                        ARRAY OPERATION COMPLEXITIES                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Access:   O(1)  [Contiguous offset index lookup]                      │
│   Traversal:O(n)  [Linearly visiting all N elements]                    │
│   Search:   O(n)  [Sequentially checking items]                         │
│   Update:   O(1)  [Direct index write]                                  │
│   Insert:   O(n)  [Shifting elements to make space]                     │
│   Delete:   O(n)  [Shifting elements to fill gap]                       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

A. Element Access — O(1)

Direct pointer arithmetic offset calculations ke zariye index target check kiya jata hai, isiliye array size chahe 10 lakh ho, element access hamesha constant time leta hai.

const arr =;
const val = arr; // O(1) Time

B. Traversal — O(n)

Array ke pehle element se shuru karke aakhri element tak ek-ek karke visit karna traversal hai.

function traverse(arr) {
    for (let i = 0; i < arr.length; i++) {
        console.log(arr[i]); // visiting every element
    }
}
  • Why O(n)? Agar array mein n elements hain, toh loop exactly n baar chalega.

4. TRAVERSAL METHODS IN JAVASCRIPT

Array par iterate karne ke multiple tarike hote hain. DSA point of view se samjho ki kab kaunsa rasta choose karna hai:

1. Classic for Loop (Best for Index-Based Control)

for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
  • Kab use karein? Jab humein array ka index modify karna ho, reverse direction mein iterate karna ho (i--), ya dynamically multiple steps jump karne hon (jaise i += 2).

2. while Loop (Best for Dynamic Pointer Conditions)

let i = 0;
while (i < arr.length) {
    console.log(arr[i]);
    i++;
}
  • Kab use karein? Jab loop ka termination condition strictly numeric boundary par nahi, balki dynamic states par depend kare (jaise pointers tab tak move karne hain jab tak left index pointer right pointer se chota ho).

3. for...of Loop (Best for Readability & Value Access)

for (const val of arr) {
    console.log(val);
}
  • Kab use karein? Jab humein index se koi lena-dena na ho aur bas array ki values ko cleanly read karna ho.

5. LINEAR SEARCH — THE CORNERSTONE SEARCHING ALGORITHM

Linear Search (sequential search) sabse basic searching algorithm hai.

Concept & Working:

Manlo humein array mein ek target value dhoondhni hai. Hum index 0 se start karenge aur array ke end tak ek-ek element ko check karte jayenge. Agar matching value mil gayi, toh uska index return kar denge, warna array finish hone par -1 return kar denge.

Target = 30
Array: [ 10 │ 25 │ 30 │ 12 ]
         0    1    2    3
Step 1: Check Index 0 -> 10 !== 30 (Aage badho)
Step 2: Check Index 1 -> 25 !== 30 (Aage badho)
Step 3: Check Index 2 -> 30 === 30 (Match Found! Return Index 2)

Manual JavaScript Implementation:

function linearSearch(arr, target) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === target) {
            return i; // Target index mil gaya
        }
    }
    return -1; // Pura array check kar liya, target nahi mila
}

Line-by-Line Explanation:

  • let i = 0: Array ke starting pointer 0 se iteration initialize hoti hai.
  • i < arr.length: Hum tab tak chalte hain jab tak indices valid bounds ke andar hain.
  • if (arr[i] === target): Har index par checked elements ko strict evaluation === se target value se match karte hain.
  • return i: Milte hi processing terminate karke index return kar dete hain.
  • return -1: Agar control loop se bahar aa gaya, iska matlab value nahi thi.

Complexity Analysis:

  • Best Case: Target index 0 par hi mil jaye. operations = 1 → O(1) Time.
  • Worst Case: Target aakhri index par ho ya array mein present na ho. pooray n elements scan karne padenge → O(n) Time.
  • Average Case: Target array ke beech mein kahin mile (around n/2 steps). constants drop karne par → O(n) Time.
  • Space Complexity: O(1) Auxiliary Space kyunki hum koi extra helper memory structures scale nahi kar rahe.

6. INSERTION & DELETION IN-DEPTH (VISUAL & SHIFTING MECHANICS)

Array contiguous block of memory hota hai, isiliye shifts compulsory hain jab hum elements starting ya middle mein manipulate karte hain.

A. INSERTION MECHANISM (Shifting Elements to the Right)

Manlo humare paas array hai `` aur humein index 1 par value `99` insert karni hai.

Initial Array:
Index:     0      1      2      3      4
        ┌──────┬──────┬──────┬──────┬──────┐
        │  10  │  20  │  30  │  40  │      │ (Vacancy at end)
        └──────┴──────┴──────┴──────┴──────┘

Step 1: Piche se shuru karke index 1 tak elements ko right shift karenge
        ko index 4 par copy kiya:
        [ 10 │ 20 │ 30 │ 40 │ 40 ]
        ko index 3 par copy kiya:
        [ 10 │ 20 │ 30 │ 30 │ 40 ]
        ko index 2 par copy kiya:
        [ 10 │ 20 │ 20 │ 30 │ 40 ]

Step 2: Ab index 1 free ho chuka hai, wahan target 99 overwrite karenge:
        [ 10 │ 99 │ 20 │ 30 │ 40 ]  <-- Insertion Complete!

Manual DSA Implementation of Insertion:

function insertAtIndex(arr, index, value) {
    const n = arr.length;
    // Right shift loops back
    for (let i = n; i > index; i--) {
        arr[i] = arr[i - 1];
    }
    arr[index] = value; // write on target vacancy
    return arr;
}
  • Beginning insertion complexity: O(n) kyunki pooray n elements ko 1 step right shift karna padta hai.
  • Middle insertion complexity: O(n) kyunki targeted location ke aage ke elements ko shift overhead face karna padta hai.
  • End insertion complexity: O(1) (amortized) kyunki piche direct empty slot par overwrite hota hai, no shifting required.

B. DELETION MECHANISM (Shifting Elements to the Left)

Manlo humare paas array hai `` aur humein index 1 se element delete karna hai.

Initial Array:
Index:     0      1      2      3      4
        ┌──────┬──────┬──────┬──────┬──────┐
        │  10  │  99  │  20  │  30  │  40  │
        └──────┴──────┴──────┴──────┴──────┘

Step 1: Index 2 se shuru karke elements ko 1 step left shift karenge
        ko index 1 par copy kiya:
        [ 10 │ 20 │ 20 │ 30 │ 40 ]
        ko index 2 par copy kiya:
        [ 10 │ 20 │ 30 │ 30 │ 40 ]
        ko index 3 par copy kiya:
        [ 10 │ 20 │ 30 │ 40 │ 40 ]

Step 2: Array ka duplicate tail element pop / truncate karenge size reduce karke:
        [ 10 │ 20 │ 30 │ 40 ] <-- Deletion Complete!

Manual Deletion Implementation:

function deleteAtIndex(arr, index) {
    const n = arr.length;
    if (index < 0 || index >= n) return arr;
    
    // Left shifting
    for (let i = index; i < n - 1; i++) {
        arr[i] = arr[i + 1];
    }
    arr.length = n - 1; // Direct resizing truncation
    return arr;
}
  • Beginning deletion complexity: O(n) because all elements must shift left to fill index 0.
  • Middle deletion complexity: O(n) due to partial shifting of suffix elements.
  • End deletion complexity: O(1) hamesha, directly tail element truncate hota hai, no shifts.

7. IMPORTANT JAVASCRIPT ARRAY METHODS

Let's dissect high-utility JS array built-ins along with their internal operational characteristics:

const fruits = ['apple', 'banana', 'cherry'];

1. push(val)

  • Purpose: Array ke very end par elements append karta hai.
  • Does it mutate? Yes, mutates original array.
  • Time Complexity: O(1) (amortized). No shifts needed.
  • Example:
    fruits.push('date'); // ['apple', 'banana', 'cherry', 'date']

2. pop()

  • Purpose: Array ke end se elements remove aur return karta hai.
  • Does it mutate? Yes, mutates original array.
  • Time Complexity: O(1).
  • Example:
    fruits.pop(); // returns 'date'

3. unshift(val)

  • Purpose: Array ke starting position (index 0) par element insert karta hai.
  • Does it mutate? Yes, mutates original array.
  • Time Complexity: O(n). Shifts entire elements rightwards.
  • Example:
    fruits.unshift('apricot'); // ['apricot', 'apple', 'banana', 'cherry']

4. shift()

  • Purpose: Array ke index 0 se element remove aur return karta hai.
  • Does it mutate? Yes, mutates original array.
  • Time Complexity: O(n). Shifts entire elements leftwards.
  • Example:
    fruits.shift(); // returns 'apricot'

5. splice(start, deleteCount, ...items)

  • Purpose: Multi-purpose tool jo elements add, remove ya replace karta hai target ranges par.
  • Does it mutate? Yes, mutates original array directly.
  • Time Complexity: O(n). Shifts internal trailing element chains.
  • Example:
    fruits.splice(1, 1, 'mango'); // replaces index 1 'banana' with 'mango'

6. slice(start, end)

  • Purpose: Array ke specific chunk range [start, end) ko sub-array copy return karta hai.
  • Does it mutate? No! Returns a shallow copy, leaving original intact.
  • Time Complexity: O(k) where k = end - start.
  • Example:
    const subset = fruits.slice(1, 3); // returns ['mango', 'cherry']

7. concat(...arrays)

  • Purpose: Multiple arrays ko link/merge karke ek new array block return karta hai.
  • Does it mutate? No! Returns a brand new array.
  • Time Complexity: O(n + m) where n, m are lengths of the arrays being merged.
  • Example:
    const combined = fruits.concat(['grape', 'kiwi']);

8. includes(val)

  • Purpose: Check karta hai ki array mein value hai ya nahi (returns boolean).
  • Does it mutate? No.
  • Time Complexity: O(n). Performs manual linear scan underneath.
  • Example:
    fruits.includes('apple'); // true

9. indexOf(val)

  • Purpose: Target element ka pehla valid matching index deta hai, warna -1.
  • Does it mutate? No.
  • Time Complexity: O(n). Performs linear traversal.
  • Example:
    fruits.indexOf('mango'); // 1

8. ARRAY OPERATIONS COMPLEXITY SUMMARY

Whiteboard par dhyan do, yeh table dimaag mein lock kar lo:

Operation Position Time Complexity Real Shifting Reason
Access Anywhere O(1) Direct index math pointer offset jump.
Search Anywhere O(n) Linear trace scan starting from index 0.
Update Anywhere O(1) Direct write to continuous indexed slot.
Insertion Beginning O(n) Must shift all n elements to the right.
Insertion Middle O(n) Must shift elements after the target index.
Insertion End O(1) (amortized) Direct append to final contiguous block.
Deletion Beginning O(n) Must shift all remaining elements left.
Deletion Middle O(n) Shift subsequent elements to close the gap.
Deletion End O(1) Direct tail truncation, no shifts needed.

9. DSA-REQUIRED JAVASCRIPT CONCEPTS

JavaScript mein memory pointer variables reference semantics follow karte hain, jo data structures mein bohot crucial hain.

A. Variable References & Mutation

JavaScript mein primitive types (numbers, strings) pass-by-value hote hain. Lekin Objects aur Arrays pass-by-reference hote hain.

let arrayA =;
let arrayB = arrayA; // reference pointer copied

arrayB.push(4);
console.log(arrayA); // Output: <-- arrayA bhi change ho gaya!

Kyunki arrayA aur arrayB dono memory mein same identical stack space address block ko point kar rahe hain.

B. Const Array Modification vs Reassignment

Bachon ko aksar confusion hoti hai: "Sir, const array ko hum push karke kaise change kar sakte hain?"

const myArr =; // address reference lock ho gaya
myArr.push(4); // ALLOWED! Elements mutate hue, reference address change nahi hua

myArr =; // ERROR! Reassignment is strictly blocked in const variables

C. Shallow Copy vs Deep Copy (Nested Array reference)

  • Shallow Copy: Pehle level ke properties ko copy karta hai.
    let original = [,];
    let shallowCopy = [...original]; // spread operator
    Agar hum first level array change karein, toh normal copy hoga. Par nested level properties reference pointers duplicate copy karti hain:
    shallowCopy.push(99); 
    console.log(original); // <-- Nested element main change reflect ho gaya!
  • Deep Copy: Har level of nested elements ko brand new arrays allocations banta hai.
    let deepCopy = JSON.parse(JSON.stringify(original));

10. BASIC PROBLEM SOLVING (TRAVERSAL & REDUCTION LOGIC)

Chalo standard DSA problems solve karte hain direct manual loops lagakar.

Problem A: Find the Sum of Array Elements

  • Understand: Humein ek array diya hai aur humein saare elements ka total sum return karna hai.
  • Approach: Ek cumulative variable sum initialized zero rakhenge. Pooray array par sequence loop trace chalakar har value add karte jayenge.
function getSum(arr) {
    let sum = 0; // sum state
    for (let i = 0; i < arr.length; i++) {
        sum += arr[i]; // adding sequentially
    }
    return sum;
}
  • Line-by-Line:
    • let sum = 0: Sum tracker variable setup kiya.
    • for (let i = 0; i < arr.length; i++): Indices start 0 se length tak scan chalta hai.
    • sum += arr[i]: Cumulative math addition.
  • Dry Run (arr =):
    • sum = 0
    • i = 0 → sum = 0 + 10 = 10
    • i = 1 → sum = 10 + 20 = 30
    • i = 2 → sum = 30 + 30 = 60
    • Returns 60.
  • Complexity: O(n) Time kyunki complete traversal execute ho raha hai. O(1) Auxiliary Space variables storage ke liye.
  • Edge Cases: Empty array [] → check constraints, return 0.

Problem B: Find Maximum and Minimum Elements in Array

  • Understand: Array mein se sabse bada (Max) aur sabse chota (Min) elements nikaalna hai.
  • Approach: Hum pehle element (arr) ko hi initial max aur min maan lenge. Phir loop chalakar check karenge ki kya koi value unse badi ya choti hai.
function findMinMax(arr) {
    if (arr.length === 0) return { min: null, max: null };
    
    let min = arr;
    let max = arr;
    
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] > max) {
            max = arr[i]; // update max
        }
        if (arr[i] < min) {
            min = arr[i]; // update min
        }
    }
    return { min, max };
}
  • Dry Run (arr =):
    • min = 5, max = 5
    • i = 1 (Value = 12) → 12 > max(5) → max = 12.
    • i = 2 (Value = 3) → 3 < min(5) → min = 3.
    • i = 3 (Value = 45) → 45 > max(12) → max = 45.
    • Returns { min: 3, max: 45 }.
  • Complexity: O(n) Time, O(1) Space.
  • Edge Cases: Single size array `` → Returns {min: 10, max: 10}.

Problem C: Reverse an Array (In-Place / Optimized)

  • Understand: Array ke elements ko reverse order mein place karna hai.
  • Approach: Two pointer approach use karke start index pointer 0 se aur end index n-1 se set karke elements swap karte huye meet karaenge center par.
function reverseArray(arr) {
    let start = 0;
    let end = arr.length - 1;
    
    while (start < end) {
        // Swapping values manually
        let temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
        
        start++;
        end--;
    }
    return arr;
}
  • Dry Run (arr =):
    • start = 0, end = 3.
    • Swap arr & arr: Array → ``.
    • start = 1, end = 2.
    • Swap arr & arr: Array → ``.
    • start = 2, end = 1 (Loop breaks). Correct!
  • Complexity: O(n) Time. O(1) Auxiliary Space kyunki humne arrays ke elements in-place change kiye.

Problem D: Check if Array is Sorted in Ascending Order

  • Understand: Check karna hai ki har element apne agle element se chota ya barabar hai (arr[i] <= arr[i+1]).
  • Approach: Adjacent linear pairs check karenge. Agar kisi bhi point par standard relation coordinate fail ho arr[i] > arr[i+1], instantly return false.
function isSorted(arr) {
    for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i] > arr[i + 1]) {
            return false; // sorted order broken
        }
    }
    return true;
}
  • Time Complexity: O(n). O(1) Space.
  • Edge Cases: Single element array ya empty array hamesha sorted hote hain.

11. COMMON MISTAKES (THE DSA RED FLAGS! ⚠️)

  1. Index vs. Value Confusion: Loop chalate waqt log i (index pointer) aur arr[i] (index ke andar ki actual value) ke beech confuse ho jate hain. Hamesha evaluate karo: key positions checking i hai ya element index value arr[i].
  2. Off-by-One Out-of-Bounds: Array ka size length hota hai par indices sirf length-1 tak access ho sakte hain. for(let i=0; i <= arr.length; i++) likhne par last step par arr[length] access hoga jo undefined return dega aur code fail ho jayega! Use < arr.length always.
  3. Modifying Array while Traversing: Loop traverse chalne ke dauran unshift ya splice manipulation steps indexes pointer position crash kar dete hain. Modifying active iterating ranges leads to buggy code.
  4. Shallow Reference Pointer mutation bugs: let copy = arr manually reference pass hai. Copy array modify karne par original update ho jayega. Copying ke liye const copy = [...arr] use karo.

12. CONNECTING TO COMPLEXITY THEORY (CHAPTER 2 CONNECTION)

Tumne notice kiya hoga ki jab hum elements starting positions par shift/remove karte hain, toh complexity linear O(n) ho jati hai.

  • Actual work behind the scenes: Memory contiguous blocks are locked consecutive sequence blocks. Agar index 0 space empty karni hai, toh computer internally har index values ko register storage par shifts move linear direction instructions execute karta hai.
  • Yahi physical shifting actions actual workload coordinate badhate hain, jisse complexity scale lines increase ho jati hai.
  • Custom loops nested iterations multiplication rule generate karti hain: outer scale N times, inner dynamic triangle M times → total complexity is O(n^2) ya sequential linear loops add up to O(n + m).

13. CLASSROOM PRACTICE PROBLEMS (YOUR TURN!)

Aao bacho, whiteboard clear hai, ab in problems ke solution trace karo. Pehle pause karke khud socho ki isme actual code and complexity bounds kya hone chahiye!

Problem 1 (Easy): Print Alternate Elements in Array

  • Problem Statement: Ek array diya hai, humein index 0 se starting alternate indices (0, 2, 4, ...) ke elements ko print karna hai.
  • Hint to Think: Hum sequential increment steps variable size badha sakte hain (i += 2).
// Solution Code
function printAlternate(arr) {
    for (let i = 0; i < arr.length; i += 2) {
        console.log(arr[i]);
    }
}
  • Complexity: O(n) Time (since loop runs approximately n/2 times, and constants are dropped). O(1) Space.

Problem 2 (Medium): Find the Second Largest Element in Array (Without Sorting)

  • Problem Statement: Array mein se second largest element dhoondho bina use sort kiye.
  • SDE Strategy to Think: Hum do trackers largest aur secondLargest initially -Infinity set karenge. Pure array par ek baar loop lagayenge:
    • Agar arr[i] > largest hai, toh pehle secondLargest ko update karo largest se, fir largest ko update karo arr[i].
    • Agar current element largest se chota hai, par secondLargest se bada hai, toh update only secondLargest.
// Solution Code
function findSecondLargest(arr) {
    if (arr.length < 2) return null;
    
    let largest = -Infinity;
    let secondLargest = -Infinity;
    
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] > largest) {
            secondLargest = largest;
            largest = arr[i];
        } else if (arr[i] < largest && arr[i] > secondLargest) {
            secondLargest = arr[i];
        }
    }
    return secondLargest === -Infinity ? null : secondLargest;
}
  • Complexity: O(n) Time (Single-pass logic). O(1) Space (no sorting space limits used).

CHAPTER END SUMMARY

Completed Topics:

  • Foundational definition of Arrays, memory offsets zero-based indexing maths.
  • JS heterogeneous arrays vs static contiguous traditional arrays.
  • Manual raw operations loops and element shifting visual mechanics.
  • Complexities of push/pop/shift/unshift/splice/slice methods.
  • Variable references, mutations, const modifications, shallow/deep copies.
  • Problem solving: Sum, Min/Max, Reverse, Check Sorted, Alternate print.

Important Takeaways:

  • Index Access hamesha constant time O(1) hota hai offset formulas ke computation optimization se.
  • Shift/Unshift/Splice linear time O(n) complexities lete hain internal contiguous blocks movements shifts calculations ke pipeline overhead se.

Common Mistakes:

  • Loop limits boundaries standard check boundaries comparison using wrong logical operations indices mismatch.
  • Reference mutation errors inside variable assignments without slice/clones.