Для поставленной задачи существуют разные решения, как на уровне реализации в коде, так и на уровне алгоритма блок-схемы. Я предлагаю реализацию только одного из возможных решений.
Самый простой способ - создать новый массив и просто заполнить его строками исходного массива, т.к. в формальном описании задачи не уточняется, что возвращается исходный же массив. Так как в C# с динамическими массивами сложно, проблема такого метода - необходимость двух пробегов по исходному массиву строк. При первом пробеге по исходному массиву программа вычисляет необходимый размер нового массива с короткими строками. При втором пробеге по исходному массиву программа заполняет данными массив с короткими строками. Именно этот вариант я решил реализовать в коде Наполнение исходного массива, вычисление размера массива с короткими строками и заполнение массива с короткими строка происходит с помощью отдельных методов В программу включены методы для отображения исходного массива и массива с короткими строками для большей очевидности работы кода, но формально они не необходимы для решения задачи
Мы могли бы после ввода каждого элемента исходного массива определять его длину. Тогда к моменту заполнения исходного массива у нас уже был бы известен размер короткого массива. Этот способ мог бы позволить избежать одного пробега по массиву, но не может быть применен при передаче исходного массива из какого-то внешнего источника, вместо ручного или случайного заполнения в самой программе.
Если предположить, что число элементов исходного массива, которые меньше 4 символов, не особенно велико, мы можем создать переменную для хранения всех коротких строк в одной строке путем конкатенации элементов исходного массива с использованием в качестве парсера символа, который не должен встретиться в строке (например - кавычки, четверной пробел и т.д). Далее нам останется разрезать эту строку и заполнить ее кусочками новый массив. Если новый массив содержит меньше элементов, чем исходный, мы выиграем в количестве пробегов. Однако мы проиграем в памяти и, сверх того, максимальная длина переменной-строки заведомо меньше, чем максимальная сумма символов в массиве строк - конкатенация может привести к переполнению.
Можно создать целочисленный массив, размер которого равен размеру исходного массива строк и заполнить его элементами "-1". Тогда, при первом пробеге исходного массива, мы можем одновременно записывать в этот целочисленный массив индексы коротких строк. При таком подходе, если новый массив содержит меньше элементов, чем исходный, мы выиграем в количестве пробегов, но проиграем в памяти.
Можно обойтись одним массивом - исходный массив можно отсортировать по длинне строк (например сортировкой вставками или даже вариантами пузырька) и запомнить индекс в котором находится первая строка в 4 символа. Далее с помощью метода Resize можно отрезать хвост с элементами длиннее трех символов и вернуть исходный массив. Мы теряем исходный массив и, в зависимости от метода сортировки и отсортированности исходного массива, скорее всего проигрываем в количестве пробегов по массиву, но несколько экономим в памяти. И выглядит это изящнее.
Каждый из вышеописанных алгоритмов может быть хоть в какой-нибудь мере реализован рекурсивными методами. Однако я не думаю (или слабо понимаю), что рекурсия может дать какой-то выигрыш в памяти или быстродействии.
Мой метод решения предложенной задачи не самый интересный или изящный. Но он довольно универсальный, относительно экономный в вопросах памяти и для него проще всего нарисовать блок-схему! Так как итоговая контрольная работа предполагает рисование блок-схемы, я решил, что это не радикальное, но важное для меня преимущество.