Сторінка 1 з 2

IT-тусовка

Додано: 7.11.12 12:21
8RydeR
Може хтось з них допоможе мені з моїм питанням? :)

Отже, є задача:
Для введённой пользователем с клавиатуры строки программа должна определить, корректно ли расставлены скобки (круглые, фигурные, квадратные). «Перемешивание» скобок (пример: «{[}]») считается некорректным вариантом.
Є код, написаний мною, який цю задачу коректно вирішує:
Spoiler
Show

Код: Виділити все

import java.util.*; public class numberKostin7 { public static void main (String[] args) { Scanner input = new Scanner(System.in); //відкриваю вхідний потік String insertedString = input.nextLine(); //зчитую стрічку з клавіатури char[] last = new char[insertedString.length()]; //ініціалізую масив довжиною в довжину введеної стрічки int countKru = 0; int countFig = 0; int countKva = 0; //счотчікі скобок різних типів int error = 0; int j = 0; //счотчік помилок і счотчік для прохода по масиву for (int i=0; i < insertedString.length(); i++) //цикл проходить по введеній стрічці { switch (insertedString.charAt(i)) { case '[': //якщо даний елемент стрічки - відкриваюча квадратна дужка last[j] = insertedString.charAt(i); //при відкриванні дужки вона записується у поточний елемент масиву j++; //счотчік масива інкрементується countKva++; //інкрементується счотчік квадратних дужок break; case '(': //виконуюються аналогічні дії, але для круглої дужки last[j] = insertedString.charAt(i); j++; countKru++; break; case '{': //виконуюються аналогічні дії, але для відкриваючої фігурної дужки last[j] = insertedString.charAt(i); j++; countFig++; break; case ']': //якщо останній знайдений елемент - закриваюча квадратна дужка j--; // декрементується счотчік масиву if (last[j] == '(' || last[j] == '{') //перевіряє, чи остання відкрита дужка була неквадратною error++; //інкрементує счотчік помилок countKva--; //декрементує счотчік відкритих квадратних дужок break; case ')': //аналогічно для закриваючої круглої дужки j--; if (last[j] == '[' || last[j] == '{') error++; countKru--; break; case '}': //аналогічно для закриваючої фігурної дужки j--; if (last[j] == '(' || last[j] == '[') error++; countFig--; break; } } System.out.println(countKru + " ( ) quantity errors"); System.out.println(countKva + " [ ] quantity errors"); System.out.println(countFig + " { } quantity errors"); System.out.println(error + " pairing errors"); } }
І є проблема:
мені не подобається те, що я відкриваю масив довжиною в цілу стрічку. Це якесь марнування ресурсів. Думаю, цю задачу можна вирішити простіше.

Питання:
як можна оптимізувати алгоритм?
якби хтось хоча би на пальцях пояснив, як оптимізувати алгоритм, ідею в код я переведу сам.

Заздалегідь вдячний!

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 12:36
Anadorr
Тут следует волноваться не из-за растраты ресурсов (размер ввода в принципе мизерный), а из-за кучи однотипных case (очень плохой стиль).
Сделай обьект, который будет держать варианты открывающих/закрывающих скобок; самый простой пример - 2 массива, openingDelimiters = [ '{','[', ...etc.. ], closingDelimiters = [ '}',']', ...etc.. ] и массив для счетчиков, и в 2х вложенных циклах делай действия проверки.
Для хранения "последних скобок" (и да, для уменьшения растраты памяти) можно использовать коллекцию типа List (а еще правильнее - Stack, он оптимизирован под добавление/удаление с конца), добавляя и удаляя из нее элементы.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 12:37
camo
Юзать динамические массивы или специальные структуры данных.
Не знаю, как там в яве, в С# есть всякие динамические списки ListArray или обобщенные коллекции List<>.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 13:40
meral
а зачем так сложно?
там есть проще алгоритм, лексический. связаный с простым подсчетом.
в нем память расходуется как o(m) где m - количество лексем(у тебя 6).

дальше (не моя) цитата которая показывает как.

при открытие скобки +1*(2^(0+индекс_открытия))
при закрытии скобки -1*(2^0+индекс_открытия)
где индекс открытия у тебя идет от 0...
Причем т.к. у тебя типов скобок несколько, то считаешь для каждой отдельно... (но индекс входимости всегда один, при открытие любой скобки мы его инкрементируем ++, при закрытии дикрементируем --)


Цитата:



Тоесть :
например [ ( ] )
Получается
"[]" 1*2^0 - 1*2^1 = 1-2 = -1
"()" 1*2^1 - 1*2^0 = 2- 1 = 1
Если показатели не равны нулю то скобки не действитель




Цитата:



пример 2 [()]
"[]" 1*2^0 - 1*2^0 = 0
"()" 1*2^1 - 1*2^1 = 0
А тут все верно...

/*
http://www.codeby.net
Autor: DarkKnight125
*/
#include <iostream>

using namespace std;

void main(void)
{
setlocale(LC_ALL,"Russian");
int Index = 0; //Идекс открытости
bool isGood = true; //Флаг правельности синтаксиса, предположи что синтаксис из начально верен
char Str[128] = {0}; //Исковая строка
double Arr[3] = {0}; //Наш массив-сумматор для скобок Arr[0] ()
//Arr[1] {}
//Arr[2] []

cout<< "Введите исходную строку: ";
cin.getline(Str,127); //Введем строку тип (a*b{ab}-c)

for (int i = 0; i<strlen(Str); i++) //Обойдем всю строку
{
if (Str == '(' || Str == ')') //Если попался один из символов круглых скобок
switch (Str) //Проверим какой
{
case '(': //Если открытие
Index++; //Увеличим индекс
Arr[0]+=pow(2.0,Index); //Прибавим к нужному эл. массива 2*текущая_входимость(индекс открытости скобки)
Index++; //Увеличим индекс
break;
case ')': //Если закрытие
Index--; //Сначало уменьшим индекс т.к. если было окрытие то индекс мы уже увеличили, а нам нужен индекс одного уровня
Arr[0]-=pow(2.0,Index); //Потом отними
}
//По аналогии все остальные
else if (Str == '{' || Str == '}')
switch (Str)
{
case '{':
Index++;
Arr[1]+=pow(2.0,Index);
break;
case '}':
Index--;
Arr[1]-=pow(2.0,Index);
}
else if (Str == '[' || Str == ']')
switch (Str)
{
case '[':
Index++;
Arr[2]+=pow(2.0,Index);
break;
case ']':
Index--;
Arr[2]-=pow(2.0,Index);
}

}

for (int i = 0; i<3; i++) //Обойдем массив и проверим все ли значение равны 0
{
if (Arr != 0)
isGood = false; //Если хотя бы одно из значений не равно нулю то значит синтаксис не верен
}

if (isGood) //Согласно флагу выведим сообщение
cout<< "Кол-во скобок соответствует синтаксису"<< endl;
else cout<< "Ошибка : Расположение скобок ошибочно"<< endl;

}

причем это выше ^^ со строчкой,в вообще задача решается с хранением трех longint и двумя проверками.если гдето стало <0 то уже неверно,если гдето стало почти максимум, то значит ты не можешь ее решить по переполнению.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 14:24
camo
а зачем так сложно?
Господи, не кипятите человеку мозг. Всего то нужно немного переписать код, причем рабочий!!!
А вы ему тут какие-то адские алгоритмы даете, причем на С!
Препод такое увидит и крышей двинется :lol:

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 14:39
meral
да куда уж проще. если для вас это сложно да и еще О УЖАС!!! на си, то топикстартер то границ не давал. и воообще алгоритм простой и на чем написан - неважно. перепиать минут 20 и отладить еще часик.

код с использованием длинных массивов для такой тривиальной задачи никак нельзя признать рабочим.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 15:18
camo
да куда уж проще. если для вас это сложно
Мне вообще до ... Обо мне речь не идет.
О УЖАС!!! на си, то топикстартер то границ не давал.
Вообще так, на секундочку, топикстартер выложил то что он наваял на яве! Я указал, что он может использовать с точки зрения шарпа, а как известно - это те же яйца, только в профиль.
алгоритм простой и на чем написан - неважно. перепиать минут 20 и отладить еще часик.
Вот я вообще категорически не понимаю, зачем полтора часа тратить на переписывание того, что уже работает, заново, чем потратить 15-20 минут на доработку кода???

Вобщем автору понаписывали тут всего, пущай выбирает, что более рационально в его случае.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 16:26
Alt
Как-то так. Не тестировал, может какие-то варианты упустил.
Spoiler
Show

Код: Виділити все

import java.util.LinkedList; public class ParenCheck { static int OPENING = 1, CLOSING = -1; static int PAREN = 0, BRACKET = 1, BRACE = 2, PAIRING = 3; static String[] desc = { "()", "[]", "{}", "Pairing" }; static int[] check(char[] s) { int[] stat = new int[4]; int sym, type; LinkedList<Integer> stack = new LinkedList<Integer>(); for(int i=0; i<s.length; i++) { switch(s[i]) { case '(': sym = PAREN; type = OPENING; break; case ')': sym = PAREN; type = CLOSING; break; case '[': sym = BRACKET; type = OPENING; break; case ']': sym = BRACKET; type = CLOSING; break; case '{': sym = BRACE; type = OPENING; break; case '}': sym = BRACE; type = CLOSING; break; default: continue; } stat[sym] += type; if(type == OPENING) { stack.push(sym); } else { if(!stack.isEmpty() && stack.peek() == sym) stack.pop(); else stat[PAIRING]++; } } stat[PAIRING] += stack.size(); return stat; } public static void main(String[] args) { if(args.length > 0) { int[] stat = check(args[0].toCharArray()); for(int i=0; i<stat.length; i++) System.out.format("%s errors: %d\n", desc[i], Math.abs(stat[i])); } } }
С нормальным форматированием здесь

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 16:34
Alt
Є код, написаний мною, який цю задачу коректно вирішує:
Нет, код некорректен. Ввод, начинающийся с открывающего символа, например ")()", выбрасывает исключение index out of bounds.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 18:23
8RydeR

при открытие скобки +1*(2^(0+индекс_открытия))
при закрытии скобки -1*(2^0+индекс_открытия)
где индекс открытия у тебя идет от 0...
Причем т.к. у тебя типов скобок несколько, то считаешь для каждой отдельно... (но индекс входимости всегда один, при открытие любой скобки мы его инкрементируем ++, при закрытии дикрементируем --)
супер, ідея зі степенем двійки сподобалася, вже цікавіше.
Ще б покопатися над тим, щоб позбавитися switch-if багаточисленних і було б ащщє супер. Подумаю над цим.
/*
http://www.codeby.net
Autor: DarkKnight125
*/
switch (Str)
{
case '[':
Index++;
Arr[2]+=pow(2.0,Index);
Index++;
break;
...
}

додав це і ще одне інкрементування, бо інакше не працює у мене цей алгоритм на папірці.


в вообще задача решается с хранением трех longint и двумя проверками.если гдето стало <0 то уже неверно,если гдето стало почти максимум, то значит ты не можешь ее решить по переполнению.

Не зрозумів :(

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 18:26
meral
ну вы читаете скобочки по одной и сохраняете результат вон тех выраженией для каждой скобочки по мере прохода.
если стало меньше нуля гдето - то это сразу фейл и можно дальше не читать.

в конце сравниваете с 0.

код не проверял,взял первый попавшийся по запросу "задача о скобках". задача кстати классическая изучается во всех курсах теории алгоритмов. к ней сводится дофига других задач оценки

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 18:27
8RydeR
Всего то нужно немного переписать код, причем рабочий!!!
Нє-а, мені хочеться оптимізувати алгоритм, а не допіліть код. Мерал толкову ідею запропонував.

Причому викладача немає, я сам вчуся ( задача стирена на http://www.kostin.ws/java).

Тому і чіткого критерію оптимізації немає. Але якось не хочеться ні гвозді забивать ескаватором, ні сваі забивать молотком. :)
Вот я вообще категорически не понимаю, зачем полтора часа тратить на переписывание того, что уже работает, заново, чем потратить 15-20 минут на доработку кода???
Щоб знати правильний для конкретного випадку метод і при цьому знати інші можливі варіанти. :)

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 18:42
meral
рекомендую прочитать или прослушать курс теории алгоритмов с первого курса.
у почти уверен что в любом университете как минимум дадут перексерить конспект. аскорее всего и не будут возражать против присутсвия на лекции.
ну и курс дискретки тоеж не помешает. а так задачками врядли получится. надо более менее цельное представление.

а по критериям - как правило рассматриваются три критерия.

1) скорость написания решения

2) ефективность по памяти(важна для задач большой размерности)

3) еффективность по количеству операций.

как правило все три взаимоисключающие.

вот тот что я вам запостил это оптимизация по памяти. зато операции там классически(при вычислении человеком) не простые(а на машине простые,ибо 2 в степени на текущей архитектуре тривиальный сдвиг а сложение одна регистровая машинная команда).

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 18:47
8RydeR
я в травні диплом бакалавра факультету комп'ютерних наук авіаційного отримав. до фєні ті лекції з конспектами разом з універом.
Spoiler
Show

Код: Виділити все

import java.util.LinkedList; public class ParenCheck { static int OPENING = 1, CLOSING = -1; static int PAREN = 0, BRACKET = 1, BRACE = 2, PAIRING = 3; static String[] desc = { "()", "[]", "{}", "Pairing" }; static int[] check(char[] s) { int[] stat = new int[4]; int sym, type; LinkedList<Integer> stack = new LinkedList<Integer>(); for(int i=0; i<s.length; i++) { switch(s[i]) { case '(': sym = PAREN; type = OPENING; break; case ')': sym = PAREN; type = CLOSING; break; case '[': sym = BRACKET; type = OPENING; break; case ']': sym = BRACKET; type = CLOSING; break; case '{': sym = BRACE; type = OPENING; break; case '}': sym = BRACE; type = CLOSING; break; default: continue; } stat[sym] += type; if(type == OPENING) stack.push(sym); else { Integer last = stack.peek(); if(last != null && last == sym) stack.pop(); else stat[PAIRING]++; } } stat[PAIRING] += stack.size(); return stat; } public static void main(String[] args) { if(args.length > 0) { int[] stat = check(args[0].toCharArray()); for(int i=0; i<stat.length; i++) System.out.format("%s errors: %d\n", desc[i], Math.abs(stat[i])); } } }
На папірці працює. Мені здається, найоптимальніший з усіх запропонованих варіантів.

ідею запам'ятав, піду писать-перевірять. :good:

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 18:48
meral
ну значит препод фиговый был. дискретка один из самых полезных прослушанных курсов.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 19:32
MaD_CameL
чуть оффтоп
Show
есть несколько знакомых, закончивших этот самый факультет нау, и все в один голос говорят, что учеба эта им ничего не дала. хотя нет, есть человек, закончивший этот факультет лет 10 назад, дык он работает в ит

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 20:37
Danila_K
Еще можно попробовать регулярными выражениями задачку решить. Кода меньше будет.
Но это, наверно, тот вариант, когда гвозди экскаватором.. : )

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 20:40
meral
о. а как реуглярным выражением?
желательно на примере длиной в 10000 скобочек.
и желательно чтоб при этом было обозримое время и хватило памяти.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 20:48
Danila_K
Для начала мне понадобится пара валидных примеров длинной 10000 скобочек..

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 21:04
8RydeR
я пробував регекспи)

чо попрощє у мене навіть виходило відфільтрувати,але вирішити задачу повністю не вийшло)

імхо, це варіант для тих, хто код в умі від А до Я пише.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 22:01
meral
Для начала мне понадобится пара валидных примеров длинной 10000 скобочек..
нефиг делать.
лови

http://pro-sip.net/temp/scobki.txt
http://pro-sip.net/temp/scobki2.txt

там не ровно 10000, скорее ближе к 20к, но это достаточно. разнообразие там низкое. а именно ровно 5,но для примера сойдет.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 7.11.12 23:14
Danila_K
можно попробовать регулярными выражениями
Не получилось :unknown:
Кроме того, как оказалось, регекспы не предназначены для вложенных структур.
Мeral, ты знал :)

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 8.11.12 22:11
BigRacer
Для введённой пользователем с клавиатуры строки программа должна определить, корректно ли расставлены скобки (круглые, фигурные, квадратные). «Перемешивание» скобок (пример: «{[}]») считается некорректным вариантом.
ну вы читаете скобочки по одной и сохраняете результат вон тех выраженией для каждой скобочки по мере прохода.
если стало меньше нуля гдето - то это сразу фейл и можно дальше не читать.
в конце сравниваете с 0.
meral немного не додумал свой вариант.
Как по мне, самым оптимальным будет решение с помощью стека.
Анализируем скобки по одной - если скобка открывающая (любого вида) - кладём в стек, если закрывающая - вытаскиваем скобку из стека и сравниваем, чтобы она была такого же типа, как только что считанная закрывающая.
Если на любом этапе вытянутая из стека открывающая скобка не соответствует считанной закрывающей (или стек пустой и нечего вытаскивать), или стек не пустой после считывания всей последовательности - значит последовательность некорректная.
Как-то так..

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 5.1.13 03:03
meral
вариант со стеком плохой.

контрпример - 500000 скобочек { и потом 499999 скобочек }

очевидно что оптимальный вариант решает его за линейное время с использованием одного слова(4байта наверно для таких границ). а стековый вариант скорее всего загнется в реале. и требует линейной памяти. ну и время тоже линейное, но больше(ибо куча операций "положить на стек"

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?

Додано: 5.1.13 11:45
Varyat
Вы Боги! Читаю - наслаждаюсь :inlove:. Вот так за час взять и переделать Вселенную :molba:! Я всегда хотел быть программистом. Но так сложилось, что работаю с людьми. По сути, реставратором. Восстанавливаю то, что создала природа, а потом оно сломалось. У меня алгоритм уже четко прописан. Степеней свободы - ноль. А вы - Творцы!