using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;
class Program
{
// The maximum number of characters we are willing to remove to achieve a match.
// Set this based on the expected level of corruption. Higher numbers mean exponentially longer runtimes.
const int MaxDeletions = 3;
// The target regex pattern for a valid date/time string.
static readonly string Pattern = @"^\d{2}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}$";
static void Main()
{
// Test cases:
// 1. Valid
// 2. 1 rogue char at start (X)
// 3. 1 rogue char in middle (X)
// 4. 2 rogue chars (Y and Z)
// 5. Corruption (missing separator) - should fail gracefully
string[] testInputs =
{
"11/10/25 17:22:31",
"X11/10/25 17:22:31",
"11/10/25 Y17:22:31Z",
"Y11/10/25 Z17:22:31",
"1110/25 17:22:31",
"A B C D 11/10/25 17:22:31" // 4 rogue chars - should hit MaxDeletions limit (3)
};
foreach (string input in testInputs)
{
Console.WriteLine(new string('-', 50));
Console.WriteLine($"Testing Input: \"{input}\"");
if (Regex.IsMatch(input, Pattern))
{
Console.WriteLine("Result: Matches the pattern (0 deletions required).");
}
else
{
Console.WriteLine($"Result: Does NOT match. Searching for minimum deletions (max {MaxDeletions})...");
FindMinimalRogueChars(input);
}
}
}
/// <summary>
/// Searches for the minimal set of characters (up to MaxDeletions) whose removal makes the input match the pattern.
/// </summary>
static void FindMinimalRogueChars(string input)
{
// We look for solutions iteratively starting from 1 deletion up to MaxDeletions.
// This ensures the first solution found is the minimal one.
for (int k = 1; k <= MaxDeletions; k++)
{
// The recursive helper function is called to find all combinations of 'k' deletions.
var rogueIndices = new List<int>();
// If the recursive search finds a match at this depth 'k', we stop immediately.
if (FindAndCheck(input, Pattern, k, 0, rogueIndices))
{
// Format the output list
var removedChars = rogueIndices.Select(i => $"'{input[i]}' at index {i}").ToList();
var validString = new string(input.Where((c, i) => !rogueIndices.Contains(i)).ToArray());
Console.WriteLine($"✅ SUCCESS: Found solution requiring {k} deletion(s).");
Console.WriteLine($" Rogue Characters: {string.Join(", ", removedChars)}");
Console.WriteLine($" Valid String: \"{validString}\"");
return; // Stop searching (since k is minimal)
}
}
// If the loop finishes without returning, no minimal solution was found within MaxDeletions.
Console.WriteLine($"❌ FAILURE: No valid solution found by removing {MaxDeletions} or fewer characters.");
}
/// <summary>
/// Recursive backtracking function to try all combinations of 'k' deletions.
/// </summary>
/// <param name="input">The original input string.</param>
/// <param name="pattern">The regex pattern.</param>
/// <param name="deletionsLeft">The number of characters still allowed to be removed.</param>
/// <param name="startIndex">The index in the input string to start looking for the next character to remove (to avoid duplicate combinations).</param>
/// <param name="currentRogues">A list tracking the indices of characters removed so far.</param>
/// <returns>True if a match is found, false otherwise.</returns>
static bool FindAndCheck(
string input,
string pattern,
int deletionsLeft,
int startIndex,
List<int> currentRogues)
{
// 1. Base Case: No more deletions allowed.
if (deletionsLeft == 0)
{
// Construct the resulting string by omitting all characters marked in currentRogues.
var testString = new string(input.Where((c, i) => !currentRogues.Contains(i)).ToArray());
// Check if the resulting string matches the pattern
return Regex.IsMatch(testString, pattern);
}
// 2. Recursive Step: Try removing the next character.
// The loop condition ensures we have enough remaining characters in the input
// to select the remaining number of characters to delete.
for (int i = startIndex;
i < input.Length - deletionsLeft + 1;
i++)
{
// ACTION: Remove the character at index 'i' (by adding its index to the list)
currentRogues.Add(i);
// RECURSE: Move to the next depth, requiring one less deletion,
// and start the search from the next index (i + 1) to ensure we only move forward
// and get unique combinations.
if (FindAndCheck(input, pattern, deletionsLeft - 1, i + 1, currentRogues))
{
return true; // Found a solution at this combination
}
// BACKTRACK: If the recursive call failed to find a match,
// undo the removal before trying the next character in the loop.
currentRogues.RemoveAt(currentRogues.Count - 1);
}
return false;
}
}