/*
- Strings in C# are immutable reference types.
- Any operation that appears to modify a string actually allocates a new string.
- For repeated modifications in a loop, use StringBuilder instead.
- Indexing a string gives a char (read-only).
*/
string s = "hello";
 
// Length — O(1)
int len = s.Length;
 
// Index access — O(1), read-only
char c = s[0]; // 'h'
 
// Convert to char array for mutation, then back to string
char[] arr = s.ToCharArray();
arr[0] = 'H';
string modified = new string(arr); // "Hello"
 
// Case conversion — O(n), allocates new string
string upper = s.ToUpper(); // "HELLO"
string lower = s.ToLower(); // "hello"
 
// Contains — O(n * m)
bool has = s.Contains("ell"); // true
 
// StartsWith / EndsWith — O(m)
bool starts = s.StartsWith("he"); // true
bool ends   = s.EndsWith("lo");   // true
 
// IndexOf / LastIndexOf — O(n); returns -1 if not found
int idx  = s.IndexOf('l');     // 2
int idx2 = s.IndexOf('l', 3);  // 3 (start search from index 3)
int last = s.LastIndexOf('l'); // 3
 
// Substring — O(k), k = length of result
string sub1 = s.Substring(1);    // "ello" (from index 1 to end)
string sub2 = s.Substring(1, 3); // "ell"  (from index 1, length 3)
 
// Range slicing (C# 8+) — O(k)
string slice1 = s[1..4]; // "ell"
string slice2 = s[2..];  // "llo"
string slice3 = s[..3];  // "hel"
 
// Replace — O(n), returns new string
string r1 = s.Replace('l', 'r');    // "herro"
string r2 = s.Replace("ll", "LL"); // "heLLo"
 
// Trim — O(n)
string padded  = "  hello  ";
string trimmed = padded.Trim();       // "hello"
string trimL   = padded.TrimStart(); // "hello  "
string trimR   = padded.TrimEnd();   // "  hello"
 
// Split — O(n)
string csv      = "a,b,,c";
string[] parts  = csv.Split(',');                                          // ["a","b","","c"]
string[] parts2 = csv.Split(',', StringSplitOptions.RemoveEmptyEntries);   // ["a","b","c"]
 
// Join — O(n * m)
string[] words = { "hello", "world" };
string joined  = string.Join(", ", words); // "hello, world"
string joined2 = string.Join("", words);   // "helloworld"
 
// Null/empty checks
bool empty = string.IsNullOrEmpty("");        // true
bool blank = string.IsNullOrWhiteSpace("  "); // true
 
// Compare — O(min(n, m))
int  cmp = string.Compare("abc", "abd"); // -1
bool eq  = string.Equals("abc", "ABC", StringComparison.OrdinalIgnoreCase); // true
 
// Type conversion
string numStr = 42.ToString();                  // "42"
int    parsed = int.Parse("42");                // 42
bool   ok     = int.TryParse("abc", out int n); // false, n = 0
 
// Padding — O(n)
string padLeft  = "42".PadLeft(5, '0');  // "00042"
string padRight = "hi".PadRight(5, '-'); // "hi---"
 
// Repeating
string rep1 = new string('a', 5);                         // "aaaaa"
string rep2 = string.Concat(Enumerable.Repeat("ab", 3)); // "ababab"
 
// Char utilities — all O(1)
char ch      = 'A';
bool isDigit  = char.IsDigit(ch);          // false
bool isLetter = char.IsLetter(ch);         // true
bool isUpper  = char.IsUpper(ch);          // true
bool isLower  = char.IsLower(ch);          // false
bool isAlNum  = char.IsLetterOrDigit(ch);  // true
bool isSpace  = char.IsWhiteSpace(' ');    // true
char toLower  = char.ToLower(ch);          // 'a'
char toUpper  = char.ToUpper('a');         // 'A'
int  digitVal = ch - '0';   // numeric value of digit char: '5' - '0' = 5
int  alphaIdx = ch - 'a';   // 0-based index of lowercase letter: 'c' - 'a' = 2
 
// Numeric constants
int    maxInt  = int.MaxValue;   // 2,147,483,647
int    minInt  = int.MinValue;   // -2,147,483,648
long   maxLong = long.MaxValue;
double inf     = double.PositiveInfinity;

/*
- Mutable string buffer. Use instead of string + in loops to avoid O(n^2) time.
- Internally uses a resizable char array.
- Append: O(1) amortized | ToString: O(n)
- Requires: using System.Text;
*/
StringBuilder sb = new StringBuilder();
 
sb.Append("hello");     // O(1) amortized
sb.Append(' ');
sb.Append(42);
sb.AppendLine("world"); // appends + newline
 
sb.Insert(5, "!");      // O(n) — shifts chars right
sb.Remove(0, 5);        // O(n) — removes chars, shifts left
sb.Replace('l', 'r');   // O(n)
 
char c  = sb[0];   // O(1)
sb[0]   = 'H';     // O(1)
int len = sb.Length; // O(1)
 
sb.Clear(); // O(1) — resets Length to 0, reuse buffer
 
string result = sb.ToString();       // O(n)
string sub    = sb.ToString(1, 3);   // O(k) — 3 chars from index 1

// Requires: using System.Linq;
int[] nums = { 3, 1, 4, 1, 5, 9, 2, 6 };
 
// ── Filtering & Searching ──────────────────────────────────────
 
// Where — O(n), lazy/deferred
var evens = nums.Where(x => x % 2 == 0); // {4, 2, 6}
 
// First / FirstOrDefault — O(n), short-circuits
int first      = nums.First(x => x > 4);            // 5
int firstOrDef = nums.FirstOrDefault(x => x > 100); // 0 (default int)
 
// Last / LastOrDefault — O(n)
int last      = nums.Last(x => x < 5);             // 2
int lastOrDef = nums.LastOrDefault(x => x > 100);  // 0
 
// Any / All — O(n); Any short-circuits
bool anyBig  = nums.Any(x => x > 8); // true
bool allPos  = nums.All(x => x > 0); // true
bool hasElems = nums.Any();          // true if non-empty
 
// Contains — O(n)
bool has5 = nums.Contains(5); // true
 
// ── Projection ──────────────────────────────────────────────────
 
// Select — O(n), lazy
var doubled = nums.Select(x => x * 2);
var indexed = nums.Select((x, i) => (i, x)); // (index, value) tuples
 
// SelectMany — flattens nested sequences, O(n * m)
int[][] matrix = { new[] { 1, 2 }, new[] { 3, 4 } };
var flat = matrix.SelectMany(row => row); // {1, 2, 3, 4}
 
// ── Aggregation ─────────────────────────────────────────────────
 
int count  = nums.Count();            // 8
int count2 = nums.Count(x => x > 3); // 4
int sum    = nums.Sum();              // 31
int min    = nums.Min();              // 1
int max    = nums.Max();              // 9
double avg = nums.Average();          // 3.875
 
string[] words = { "hi", "hello", "hey" };
int minLen = words.Min(w => w.Length); // 2 — min of projected values
 
// Aggregate (fold/reduce) — O(n)
int product = nums.Aggregate(1, (acc, x) => acc * x);
int sumAgg  = nums.Aggregate(0, (acc, x) => acc + x);
 
// ── Sorting ─────────────────────────────────────────────────────
 
// OrderBy / OrderByDescending — O(n log n), does not modify original
var asc   = nums.OrderBy(x => x);
var desc  = nums.OrderByDescending(x => x);
 
// Secondary sort with ThenBy
var byLen = words.OrderBy(w => w.Length).ThenBy(w => w);
 
// ── Distinct / Skip / Take ───────────────────────────────────────
 
var unique  = nums.Distinct();       // removes duplicates using HashSet internally
var skipped = nums.Skip(2);          // skips first 2
var taken   = nums.Take(3);          // takes first 3
var page    = nums.Skip(2).Take(3);  // pagination pattern
 
// ── Grouping ─────────────────────────────────────────────────────
 
// GroupBy — O(n); each group has a Key and is IEnumerable<T>
var grouped = nums.GroupBy(x => x % 2 == 0 ? "even" : "odd");
foreach (var group in grouped)
    Console.WriteLine($"{group.Key}: {string.Join(",", group)}");
 
// Frequency map pattern
Dictionary<int, int> freq = nums
    .GroupBy(x => x)
    .ToDictionary(g => g.Key, g => g.Count());
 
// ── Set Operations ───────────────────────────────────────────────
 
int[] a = { 1, 2, 3 };
int[] b = { 2, 3, 4 };
var union     = a.Union(b);     // {1, 2, 3, 4}
var intersect = a.Intersect(b); // {2, 3}
var except    = a.Except(b);    // {1}
 
// ── Zip ──────────────────────────────────────────────────────────
 
// Merges two sequences element-by-element; stops at the shorter one — O(min(n, m))
int[] xs = { 1, 2, 3 };
int[] ys = { 10, 20, 30 };
var zipped = xs.Zip(ys, (x, y) => x + y); // {11, 22, 33}
 
// ── Conversion ───────────────────────────────────────────────────
 
List<int>    list    = nums.ToList();
int[]        array   = nums.ToArray();
HashSet<int> hashSet = nums.ToHashSet();
 
// ToDictionary — O(n); throws on duplicate keys
int[] unique2 = { 1, 2, 3 };
Dictionary<int, int> squares = unique2.ToDictionary(x => x, x => x * x);
 
// ── Generating Sequences ─────────────────────────────────────────
 
var range = Enumerable.Range(0, 5);   // {0, 1, 2, 3, 4}
var zeros = Enumerable.Repeat(0, 5);  // {0, 0, 0, 0, 0}
 
// Initialize DP array to -1
int[] dp = Enumerable.Repeat(-1, n).ToArray();

/*
- All individual bitwise operations are O(1).
- Useful for: subset enumeration, toggling flags, parity, power-of-two checks, XOR tricks.
*/
 
// ── Core Operators ───────────────────────────────────────────────
 
// &  AND:  1 if both bits are 1
// |  OR:   1 if at least one bit is 1
// ^  XOR:  1 if bits differ
// ~  NOT:  flips all bits
// << left shift:  n << k  ==  n * 2^k
// >> right shift: n >> k  ==  n / 2^k
 
int x = 0b_1010; // 10
int y = 0b_1100; // 12
 
int andR   = x & y;  // 0b_1000 = 8
int orR    = x | y;  // 0b_1110 = 14
int xorR   = x ^ y;  // 0b_0110 = 6
int notR   = ~x;      // -11 (two's complement)
int lShift = x << 1;  // 20
int rShift = x >> 1;  // 5
 
// ── Common Bit Tricks ────────────────────────────────────────────
 
// Check if bit i is set
bool isSet = ((n >> i) & 1) == 1;
 
// Set bit i to 1
n = n | (1 << i);
 
// Clear bit i to 0
n = n & ~(1 << i);
 
// Toggle bit i
n = n ^ (1 << i);
 
// Check if n is a power of 2
// n & (n-1) clears the lowest set bit; result is 0 iff exactly one bit was set
bool isPow2 = n > 0 && (n & (n - 1)) == 0;
 
// Isolate the lowest set bit (used in Fenwick trees)
int lowest = n & (-n);
 
// Clear the lowest set bit
n = n & (n - 1);
 
// Count set bits — Method 1: Brian Kernighan O(k), k = set bit count
int count = 0, temp = n;
while (temp != 0) { count++; temp &= temp - 1; }
 
// Count set bits — Method 2: hardware popcount O(1), .NET 5+
using System.Numerics;
int popcount = BitOperations.PopCount((uint)n);
 
/*
- XOR identities:
    x ^ x == 0  (same value cancels)
    x ^ 0 == x  (identity)
- Find the single non-duplicate when all others appear exactly twice.
- O(n) time, O(1) space.
*/
int[] arr2 = { 2, 3, 5, 3, 2 };
int unique = 0;
foreach (int val in arr2) unique ^= val; // 5
 
// XOR swap (only for distinct variables, not same memory location)
int p = 5, q = 9;
p ^= q; q ^= p; p ^= q; // p = 9, q = 5
 
// Enumerate ALL subsets of n elements using bitmasks — O(2^n * n)
// Bit i = 1 means element i is in the subset
int n2 = 3;
for (int mask = 0; mask < (1 << n2); mask++)
{
    for (int i = 0; i < n2; i++)
        if ((mask >> i & 1) == 1)
            Console.Write(i + " ");
    Console.WriteLine();
}
 
// Enumerate all non-empty subsets of a given mask — O(3^n) total across all masks
for (int sub = mask; sub > 0; sub = (sub - 1) & mask)
{
    // process subset 'sub'
}
 
// Leading / trailing zero counts (.NET 5+)
int leading  = BitOperations.LeadingZeroCount((uint)n);
int bitLen   = 32 - BitOperations.LeadingZeroCount((uint)n); // effective bit length
int trailing = BitOperations.TrailingZeroCount((uint)n);     // position of lowest set bit