Array

max element of an array

#include <iostream>
using namespace std;

int findMax(int arr[], int size) {
    // ১. প্রথম এলিমেন্টকে ম্যাক্সিমাম ধরে নাও
    int max = arr[0];

    // ২. লুপ চালিয়ে বাকিদের সাথে তুলনা করো
    for (int i = 1; i < size; i++) {
        if (arr[i] > max) {
            max = arr[i]; // নতুন বড় মান পেলে আপডেট করো
        }
    }
    return max;
}

int main() {
    int nums[] = {12, 45, 2, 67, 34};
    int size = sizeof(nums) / sizeof(nums[0]);

    cout << "Maximum Element: " << findMax(nums, size); // Output: 67

    return 0;
}

Second Largest Element

int findSecondLargest(int arr[], int size) {

  if(size <2) return -1;
  int largest = INT_MIN, secondLargest = INT_MIN;

  for(int i=0; i<size; i++){
    if(arr[i] >largest){
      secondLargest = largest;
      largest = arr[i];
    }else if(arr[i]> secondLargest && arr[i] !=largest){
      secondLargest = arr[i];
    }
  }
  return secondLargest == INT_MIN ? -1 : secondLargest;
}

Kth Largest Element in an Array

  void moveZeroes(vector<int>& nums) {
    int lastNonZeroFoundAt = 0;

    for (int i = 0; i < nums.size(); i++) {
        if (nums[i] != 0) {
            nums[lastNonZeroFoundAt] = nums[i];
            lastNonZeroFoundAt++;
        }
    }

    for (int i = lastNonZeroFoundAt; i < nums.size(); i++) {
        nums[i] = 0;
    }
    }

হিপ আসলে কী? (The Priority Ladder)

সাধারণত অ্যারেতে ডাটা থাকে ছড়ানো-ছিটানো। কিন্তু হিপ হলো ডাটা রাখার এমন একটা স্মার্ট কায়দা যেখানে সবার একটা প্রায়োরিটি বা পাওয়ার থাকে।

হিপ কেন দরকার? (The Efficiency Story)

মনে করো, তোমার কাছে ১ লাখ ডাটা আছে। তোমাকে বলা হলো সবচেয়ে বড় সংখ্যাটা দাও।

মেমোরিতে কাহিনীটা কীভাবে ঘটে? (The Visual Tree)

হিপ দেখতে একটা Binary Tree-এর মতো। এর দুইটা নিয়ম আছে:

মজার ব্যাপার: যদিও আমরা এটাকে “গাছ” বলছি, কম্পিউটার কিন্তু এটাকে মেমোরিতে একটা সাধারণ অ্যারে হিসেবেই রাখে! শুধু ইনডেক্সিং এর একটা ম্যাজিক ব্যবহার করে:

যখনই দেখবে প্রশ্নে বলা আছে:

C++ STL-এ priority_queue ব্যবহার করে আমরা হিপের ৩টি প্রধান কাজ করি। চলো একটা Min-Heap (যেখানে ছোট সংখ্যা উপরে থাকে) দিয়ে অপারেশনগুলো দেখি:

push(x) - নতুন সদস্য যোগ করা

যখন তুমি একটা নতুন সংখ্যা হিপে ঢোকাও, সে সরাসরি উপরে গিয়ে বসে না। সে গাছের একদম শেষে ঢোকে এবং তারপর তার বাবার (Parent) সাথে তুলনা করে দেখে সে ছোট কি না। যদি ছোট হয়, সে বাবার সাথে জায়গা বদল করে উপরে উঠে আসে। একে বলে “Heapify Up”।

pop() - মাথা ছেঁটে ফেলা

হিপে আমরা মাঝখান থেকে কিছু মুছতে পারি না। সবসময় সবচেয়ে উপরের (Root) এলিমেন্টটা মুছি।

top() - রাজাকে দেখা

এটি শুধু বলে দেয় এই মুহূর্তে হিপের মাথায় কে বসে আছে। এটা কোনো কিছু পরিবর্তন করে না।

কেন minHeap ব্যবহার করলাম? (The Strategy)

আমাদের লক্ষ্য হলো পুরো অ্যারের মধ্যে সেরা $k$ জন (Top $k$) বড় সংখ্যাকে খুঁজে বের করা।

maxHeap ব্যবহার করলে কী সমস্যা হতো?

তুমি যদি maxHeap ব্যবহার করো:

Constraints (সীমাবদ্ধতা)

  1. 1 <= nums.length <= 10^5 এর মানে হলো অ্যারেতে কমপক্ষে ১টি সংখ্যা থাকবে এবং সর্বোচ্চ ১ লাখ ($10^5$) সংখ্যা থাকতে পারে।
    • গুরুত্ব: যদি তুমি $O(n^2)$ লজিক ব্যবহার করো (যেমন লুপের ভেতর লুপ), তবে $10^5 \times 10^5 = 10,000,000,000$ বার কাজ করতে হবে। কম্পিউটার ১ সেকেন্ডে সাধারণত $10^8$ বার কাজ করতে পারে। তাই $O(n^2)$ কোড চালালে Time Limit Exceeded (TLE) খাবে। তোমাকে এমন কোড লিখতে হবে যা $O(n)$ বা $O(n \log n)$ এ কাজ শেষ করে।
  2. -2^31 <= nums[i] <= 2^31 - 1 এটি বলছে অ্যারের ভেতরে যে সংখ্যাগুলো থাকবে সেগুলোর মান কত বড় বা ছোট হতে পারে।
    • গুরুত্ব: 2^31 - 1 হলো একটি সি++ int ভেরিয়েবলের সর্বোচ্চ ধারণক্ষমতা। এর মানে হলো তুমি এই সংখ্যাগুলো রাখার জন্য সাধারণ int ব্যবহার করতে পারবে, তোমাকে long long নেওয়ার প্রয়োজন নেই। তবে যোগ-বিয়োগ করার সময় সাবধান থাকতে হবে যেন মানটি এর চেয়ে বড় না হয়ে যায়।
  3. 0 <= k <= 10^5 এর মানে তোমাকে সর্বোচ্চ ১ লাখ বার রোটেট করতে বলা হতে পারে।
    • গুরুত্ব: আমি যে Modulo Trick ($k = k \% n$) এর কথা বলেছিলাম, সেটা এখানে খুব জরুরি। ধরো অ্যারের সাইজ ৫, কিন্তু তোমাকে বলা হলো ১ লাখ বার রোটেট করতে। তুমি যদি ১ লাখ বার লুপ চালাও, তবে সময় নষ্ট হবে। কিন্তু $100,000 \% 5 = 0$ করলে তুমি ১ সেকেন্ডেই বুঝে যাবে যে আসলে কিছুই করতে হবে না!