Strings & Pattern Basics

স্ট্রিং ও প্যাটার্ন

Read: ~30 min Beginner 7 practice problems Live C++ runner

1. What Is a String, Really?

A string is just an array of characters with a special "I am done" marker. In C, that marker is the null byte '\0'; in C++ std::string stores its length explicitly so it does not need a terminator. Everything text-related — your bKash SMS, a Codeforces problem statement, the URL bar of your browser — is internally a string.

স্ট্রিং মানে কেবল কতগুলো character-এর array, যার শেষে একটি বিশেষ "শেষ হলো" চিহ্ন থাকে। C-তে এই চিহ্ন '\0'; কিন্তু C++-এর std::string length আলাদাভাবে রাখে — তাই terminator লাগে না। আপনার bKash SMS, Codeforces-এর প্রশ্ন, browser-এর URL — সবই ভেতরে ভেতরে string।
Module insight Naive pattern matching O(nm) — পরে আমরা KMP দিয়ে এটি O(n+m) করব।

2. char[] vs std::string

A C-style string char s[] = "hello"; is 6 bytes: 'h','e','l','l','o','\0'. Functions like strlen count bytes until they see the null terminator — that is O(n). By contrast, std::string s = "hello"; s.size(); is O(1) because the length is stored.

C-style string char s[] = "hello"; = 6 byte (শেষে '\0' সহ)। strlen '\0' পর্যন্ত গুনে চলে — O(n)। কিন্তু std::string::size() O(1), কারণ length আগেই সংরক্ষিত আছে। প্রতিদিনের কোডে std::string ব্যবহার করুন; C-style শুধু low-level কাজে।
Operationchar[]std::string
lengthO(n) (strlen)O(1) (.size())
appendmanual + bounds risk+=, amortised O(1) per char
comparestrcmp== operator
safetybuffer overflow riskauto-resize, safe

3. Naive Pattern Matching

Given a text T of length n and a pattern P of length m, we want every index in T where P matches. The naive method slides P over T one position at a time and compares character-by-character — worst-case O(nm).

Text T (length n) এবং pattern P (length m) দিলে, যেখানে যেখানে P মেলে সেই index-গুলো বের করতে হবে। Naive পদ্ধতি: P-কে এক ধাপ করে slide করে character-by-character compare — worst-case O(nm)। পরের module-এ আমরা KMP শিখব যা এটিকে O(n+m) করে দেয়।
Text: A B C A B A B C A B A Pattern: A B A B C A B C A B A B C A B A A B A B C Match at index 3 Figure 7.1 — Naive matching slides the pattern one step at a time and compares character-by-character।

4. Demo 1 — All Match Positions (Naive)

naive_match.cpp
#include <bits/stdc++.h>
using namespace std;

vector<int> naiveMatch(const string& T, const string& P) {
    vector<int> pos;
    int n = T.size(), m = P.size();
    for (int i = 0; i + m <= n; i++) {
        int j = 0;
        while (j < m && T[i + j] == P[j]) j++;
        if (j == m) pos.push_back(i);
    }
    return pos;
}

int main() {
    string T = "ABCABABCABABABABCABAB", P = "ABAB";
    auto r = naiveMatch(T, P);
    cout << "Matches at: ";
    for (int p : r) cout << p << " ";
    cout << "\n";
    return 0;
}

5. Demo 2 — Anagram Check & Longest Common Prefix

Two strings are anagrams if one is a rearrangement of the other. The fastest way: count character frequencies in a 26-element array. LCP (longest common prefix) of an array of strings is found by scanning columns.

দুটি string anagram যদি একটিকে rearrange করে অপরটি বানানো যায়। দ্রুততম উপায়: 26-element-এর frequency array দিয়ে গুনে compare করা। LCP (longest common prefix) বের করতে column-by-column চেক করতে হয়।
anagram_lcp.cpp
#include <bits/stdc++.h>
using namespace std;

bool isAnagram(const string& a, const string& b) {
    if (a.size() != b.size()) return false;
    int f[26] = {0};
    for (char c : a) f[c - 'a']++;
    for (char c : b) f[c - 'a']--;
    for (int i = 0; i < 26; i++) if (f[i]) return false;
    return true;
}

string longestCommonPrefix(vector<string>& v) {
    if (v.empty()) return "";
    string p = v[0];
    for (int i = 1; i < (int)v.size(); i++) {
        int k = 0;
        while (k < (int)p.size() && k < (int)v[i].size() && p[k] == v[i][k]) k++;
        p = p.substr(0, k);
        if (p.empty()) break;
    }
    return p;
}

int main() {
    cout << isAnagram("listen", "silent") << "\n";
    vector<string> v = {"flower", "flow", "flight"};
    cout << longestCommonPrefix(v) << "\n";
    return 0;
}

6. Palindromes & the Bangla UTF-8 Trap

A palindrome reads the same forwards and backwards: "madam", "racecar". The check is a two-pointer walk. But beware — Bangla text in UTF-8 uses multiple bytes per visual character. "কথা" is 9 bytes, not 3! Walking it byte-by-byte will produce nonsense.

Palindrome মানে যা সামনে ও পিছনে একই — "madam", "racecar"। সরল two-pointer পদ্ধতিতে চেক হয়। কিন্তু সাবধান — Bangla text UTF-8-এ থাকে, যেখানে এক visible character একাধিক byte দখল করে। "কথা" প্রকৃত পক্ষে 9 byte! তাই Bangla string-কে byte-by-byte না ঘুরে UTF-8 codepoint হিসেবে decode করতে হয় (পরে আমরা ICU/codecvt দেখব)।
Pitfall: s.size() on a Bangla string returns byte count, not character count. For competitive programming, this is usually fine because problems use ASCII. But for real apps (bKash, Pathao SMS templates), use a UTF-8 aware library.

7. std::string Toolbox

substr(p, len)
Extract a slice — O(len)।
find(s)
First occurrence or npos।
+ / +=
Concatenate, amortised O(n)।
sort(s.begin(), s.end())
Sort characters — O(n log n)।
reverse(s.begin(), s.end())
In-place reverse — O(n)।
==
Lexicographic compare — O(min(n,m))।

8. Practice Problems

  1. Count the number of vowels in a string.
    একটি string-এ vowel-এর সংখ্যা গুনুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans1.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        string s = "Bangladesh University of Engineering and Technology";
        int c = 0;
        for (char ch : s) {
            char x = tolower(ch);
            if (x=='a'||x=='e'||x=='i'||x=='o'||x=='u') c++;
        }
        cout << c << "\n";
    }
  2. Reverse the words in a sentence (e.g., "I love DSA" → "DSA love I").
    একটি বাক্যের শব্দগুলো reverse করুন (যেমন "I love DSA" → "DSA love I")।
    ✨ Show Answer (উত্তর দেখুন)
    ans2.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        string s = "I love DSA from Dhaka";
        stringstream ss(s);
        vector<string> w; string tok;
        while (ss >> tok) w.push_back(tok);
        reverse(w.begin(), w.end());
        for (int i = 0; i < (int)w.size(); i++) cout << w[i] << (i+1<(int)w.size()?" ":"\n");
    }
  3. Check if a string is a palindrome ignoring spaces, punctuation and case.
    Space, punctuation ও case উপেক্ষা করে palindrome কিনা যাচাই করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans3.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        string s = "A man, a plan, a canal: Panama";
        int l = 0, r = s.size() - 1;
        bool ok = true;
        while (l < r) {
            while (l < r && !isalnum(s[l])) l++;
            while (l < r && !isalnum(s[r])) r--;
            if (tolower(s[l]) != tolower(s[r])) { ok = false; break; }
            l++; r--;
        }
        cout << (ok ? "YES" : "NO") << "\n";
    }
  4. Find the longest palindromic substring (brute-force O(n³)).
    Longest palindromic substring বের করুন (brute-force O(n³))।
    ✨ Show Answer (উত্তর দেখুন)
    ans4.cpp
    #include <bits/stdc++.h>
    using namespace std;
    bool isPal(const string& s,int l,int r){while(l<r){if(s[l++]!=s[r--]) return false;}return true;}
    int main() {
        string s = "babad", best = "";
        int n = s.size();
        for (int i = 0; i < n; i++)
            for (int j = i; j < n; j++)
                if (isPal(s, i, j) && j - i + 1 > (int)best.size())
                    best = s.substr(i, j - i + 1);
        cout << best << "\n";
    }
  5. Find the first non-repeating character in a string.
    String-এ প্রথম non-repeating character খুঁজুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans5.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        string s = "leetcode";
        int f[256] = {0};
        for (char c : s) f[(int)c]++;
        char ans = '?';
        for (char c : s) if (f[(int)c] == 1) { ans = c; break; }
        cout << ans << "\n";
    }
  6. Check whether two strings are anagrams using a 26-int frequency array.
    26-int frequency array দিয়ে দুটি string anagram কিনা যাচাই করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans6.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        string a = "anagram", b = "nagaram";
        if (a.size() != b.size()) { cout << "NO\n"; return 0; }
        int f[26] = {0};
        for (char c : a) f[c-'a']++;
        for (char c : b) f[c-'a']--;
        bool ok = true;
        for (int i = 0; i < 26; i++) if (f[i]) ok = false;
        cout << (ok ? "YES" : "NO") << "\n";
    }
  7. Implement strStr (return index of first occurrence of needle in haystack, or -1).
    strStr বানান — haystack-এ needle প্রথম যেখানে আছে সেই index, না থাকলে -1।
    ✨ Show Answer (উত্তর দেখুন)
    ans7.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int strStr(const string& H, const string& N) {
        int n = H.size(), m = N.size();
        if (m == 0) return 0;
        for (int i = 0; i + m <= n; i++) {
            int j = 0;
            while (j < m && H[i+j] == N[j]) j++;
            if (j == m) return i;
        }
        return -1;
    }
    int main() {
        cout << strStr("sadbutsad", "sad") << "\n";
        cout << strStr("hello", "world") << "\n";
    }

Summary — Module 07

Strings are arrays of characters; std::string tracks length explicitly so most operations are convenient and fast. Naive pattern matching is simple but O(nm) — fine for short patterns, disastrous for long ones. Frequency arrays solve anagrams and many counting problems in O(n). For Bangla text, remember UTF-8 multi-byte encoding — byte-level loops will mis-handle characters.

String মানে character-এর array; std::string length আলাদা রাখে — তাই দ্রুত। Naive pattern matching সরল হলেও O(nm), বড় pattern-এ TLE। Frequency array দিয়ে anagram ও counting সমস্যা O(n)-এ সমাধান হয়। Bangla text-এ UTF-8 multi-byte — byte-loop বিভ্রান্ত করবে, সাবধান।

Next Module → Linked Lists — pointer-এর জাদু এবং reverse-এর কৌশল।