#2 - Arrays and Strings - Data Structures and Algorithms using C++ | Akash Vishwakarma

#2 - Arrays and Strings - Data Structures and Algorithms using C++ | Akash Vishwakarma

4K views
Summary
Hi its me Akash Vishwakarma, This is Article No #2 of Our DSA Series on Skytup. In this Article We will learn about C++ Fundamentals. This article is written with the help of Ai Tools and some of my own expertise 🙏.

Arrays and Strings: Concepts, Techniques, and Interview Questions

By: Developer Akash

Introduction

Arrays and strings are fundamental data structures in programming, providing the foundation for solving many complex problems efficiently. This article explores key concepts, advanced techniques, and problem-solving strategies associated with arrays and strings, making it a comprehensive guide for students, professionals, and interview preparation.

Basic Operations on Arrays

1. Traversal

Traversal refers to accessing each element of an array once. For example:


// Example in C++
int arr[] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
    cout << arr[i] << " ";
}

            

2. Insertion

Inserting an element into an array involves shifting elements and placing the new element in the desired position.


// Insert 10 at index 2 in C++
int arr[6] = {1, 2, 3, 4, 5};
int pos = 2, n = 5, element = 10;

for (int i = n; i > pos; i--) {
    arr[i] = arr[i - 1];
}
arr[pos] = element;

            

3. Deletion

Deleting an element involves shifting elements to fill the gap left by the removed element.


// Delete element at index 2
int arr[] = {1, 2, 3, 4, 5};
int pos = 2, n = 5;

for (int i = pos; i < n - 1; i++) {
    arr[i] = arr[i + 1];
}

            

Multi-Dimensional Arrays

Multi-dimensional arrays store data in rows and columns (2D arrays) or more dimensions. They are widely used for grid-like problems.


// Declaring a 2D array
int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

            

Advanced Techniques for Arrays and Strings

1. Sliding Window Technique

The sliding window is a powerful technique to solve problems like finding subarrays or substrings that meet specific conditions.


// Maximum sum of subarray of size k
int maxSum(int arr[], int n, int k) {
    int max_sum = 0, window_sum = 0;
    for (int i = 0; i < k; i++) {
        window_sum += arr[i];
    }
    max_sum = window_sum;
    for (int i = k; i < n; i++) {
        window_sum += arr[i] - arr[i - k];
        max_sum = max(max_sum, window_sum);
    }
    return max_sum;
}

            

2. Two-Pointer Technique

This technique is used to solve problems involving sorted arrays, like finding pairs that sum to a target.


// Find if a pair sums to target
bool hasPair(int arr[], int n, int target) {
    int left = 0, right = n - 1;
    while (left < right) {
        int sum = arr[left] + arr[right];
        if (sum == target) return true;
        else if (sum < target) left++;
        else right--;
    }
    return false;
}

            

String Manipulation

1. Palindromes

A palindrome reads the same backward and forward. To check if a string is a palindrome:


bool isPalindrome(string s) {
    int left = 0, right = s.length() - 1;
    while (left < right) {
        if (s[left] != s[right]) return false;
        left++; right--;
    }
    return true;
}

            

2. Anagrams

Two strings are anagrams if they contain the same characters in a different order. Use frequency counts to check for anagrams.


bool isAnagram(string s1, string s2) {
    if (s1.length() != s2.length()) return false;
    int count[26] = {0};
    for (char c : s1) count[c - 'a']++;
    for (char c : s2) {
        if (--count[c - 'a'] < 0) return false;
    }
    return true;
}

            

3. Pattern Matching (KMP Algorithm)

The Knuth-Morris-Pratt (KMP) algorithm efficiently finds substrings by preprocessing the pattern.


void computeLPS(string pattern, int lps[]) {
    int length = 0, i = 1;
    lps[0] = 0;
    while (i < pattern.length()) {
        if (pattern[i] == pattern[length]) {
            lps[i++] = ++length;
        } else {
            if (length != 0) length = lps[length - 1];
            else lps[i++] = 0;
        }
    }
}

            

Subarray Problems

Kadane’s Algorithm

This algorithm finds the maximum sum of a contiguous subarray in O(n) time.


int kadane(int arr[], int n) {
    int max_sum = INT_MIN, current_sum = 0;
    for (int i = 0; i < n; i++) {
        current_sum = max(arr[i], current_sum + arr[i]);
        max_sum = max(max_sum, current_sum);
    }
    return max_sum;
}

            

Interview Questions and Answers

  1. Explain the differences between arrays and linked lists.

    Answer: Arrays are a collection of elements stored in contiguous memory locations, allowing random access with an index. Linked lists consist of nodes, where each node contains a data field and a pointer to the next node. Arrays offer constant-time access for elements but have a fixed size, while linked lists provide dynamic size and efficient insertion/deletion but require sequential access.

  2. How does the sliding window technique work? Provide examples.

    Answer: The sliding window technique involves maintaining a subset of elements within a "window" and moving it across the array. For example, to find the maximum sum of a subarray of size k, calculate the sum of the first k elements and adjust the sum by adding the next element and removing the first element of the previous window.

    
    // Example in C++
    int maxSum(int arr[], int n, int k) {
        int max_sum = 0, window_sum = 0;
        for (int i = 0; i < k; i++) {
            window_sum += arr[i];
        }
        max_sum = window_sum;
        for (int i = k; i < n; i++) {
            window_sum += arr[i] - arr[i - k];
            max_sum = max(max_sum, window_sum);
        }
        return max_sum;
    }
    
                
  3. Write a function to check if two strings are rotations of each other.

    Answer: Concatenate the first string with itself and check if the second string is a substring of this concatenated string.

    
    bool isRotation(string s1, string s2) {
        if (s1.length() != s2.length()) return false;
        string temp = s1 + s1;
        return temp.find(s2) != string::npos;
    }
    
                
  4. What are the advantages of Kadane's Algorithm over brute-force methods?

    Answer: Kadane's Algorithm finds the maximum sum of a contiguous subarray in O(n) time, while brute-force methods take O(n^2) or O(n^3) time. It avoids unnecessary calculations by keeping track of the current sum and maximum sum.

  5. Implement the KMP algorithm and explain its time complexity.

    Answer: The KMP algorithm preprocesses the pattern into an LPS (Longest Prefix Suffix) array to skip unnecessary comparisons. Its time complexity is O(n + m), where n is the text length and m is the pattern length.

    
    void computeLPS(string pattern, int lps[]) {
        int length = 0, i = 1;
        lps[0] = 0;
        while (i < pattern.length()) {
            if (pattern[i] == pattern[length]) {
                lps[i++] = ++length;
            } else {
                if (length != 0) length = lps[length - 1];
                else lps[i++] = 0;
            }
        }
    }
    
                
  6. How do you reverse a string in place?

    Answer: Use two pointers, one starting at the beginning and the other at the end, and swap their values while moving the pointers towards the center.

    
    void reverseString(char str[]) {
        int left = 0, right = strlen(str) - 1;
        while (left < right) {
            swap(str[left], str[right]);
            left++;
            right--;
        }
    }
    
                
  7. Find the longest palindromic substring in a given string.

    Answer: Use dynamic programming or expand around each character as the center. Expanding around the center is efficient with O(n^2) complexity.

    
    string longestPalindrome(string s) {
        int start = 0, maxLength = 0;
        for (int i = 0; i < s.length(); i++) {
            int len1 = expandAroundCenter(s, i, i);   // Odd length
            int len2 = expandAroundCenter(s, i, i+1); // Even length
            int len = max(len1, len2);
            if (len > maxLength) {
                maxLength = len;
                start = i - (len - 1) / 2;
            }
        }
        return s.substr(start, maxLength);
    }
    
    int expandAroundCenter(string s, int left, int right) {
        while (left >= 0 && right < s.length() && s[left] == s[right]) {
            left--; right++;
        }
        return right - left - 1;
    }
    
                
  8. Given an array of integers, find all unique triplets that sum to zero.

    Answer: Use sorting and a two-pointer approach to efficiently find unique triplets.

    
    vector> threeSum(vector& nums) {
        sort(nums.begin(), nums.end());
        vector> result;
        for (int i = 0; i < nums.size() - 2; i++) {
            if (i > 0 && nums[i] == nums[i-1]) continue;
            int left = i + 1, right = nums.size() - 1, target = -nums[i];
            while (left < right) {
                int sum = nums[left] + nums[right];
                if (sum == target) {
                    result.push_back({nums[i], nums[left], nums[right]});
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    left++; right--;
                } else if (sum < target) left++;
                else right--;
            }
        }
        return result;
    }
    
                
  9. Explain how you can use hashing to solve anagram problems efficiently.

    Answer: Use a frequency count of characters as the key in a hash map. If two strings have the same character frequency, they are anagrams.

    
    bool isAnagram(string s1, string s2) {
        if (s1.length() != s2.length()) return false;
        unordered_map freq;
        for (char c : s1) freq[c]++;
        for (char c : s2) {
            if (--freq[c] < 0) return false;
        }
        return true;
    }