Сторінка 1 з 2
IT-тусовка
Додано: 7.11.12 12:21
8RydeR
Може хтось з них допоможе мені з моїм питанням?
Отже, є задача:
Для введённой пользователем с клавиатуры строки программа должна определить, корректно ли расставлены скобки (круглые, фигурные, квадратные). «Перемешивание» скобок (пример: «{[}]») считается некорректным вариантом.
Є код, написаний мною, який цю задачу коректно вирішує:
Код: Виділити все
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
а зачем так сложно?
Господи, не кипятите человеку мозг. Всего то нужно немного переписать код, причем рабочий!!!
А вы ему тут какие-то адские алгоритмы даете, причем на С!
Препод такое увидит и крышей двинется

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
Как-то так. Не тестировал, может какие-то варианты упустил.
Код: Виділити все
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
я в травні диплом бакалавра факультету комп'ютерних наук авіаційного отримав. до фєні ті лекції з конспектами разом з універом.
Код: Виділити все
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]));
}
}
}
На папірці працює. Мені здається, найоптимальніший з усіх запропонованих варіантів.
ідею запам'ятав, піду писать-перевірять.

Re: Кажуть, на велокиєві багато працівників ІТ-сфери?
Додано: 7.11.12 18:48
meral
ну значит препод фиговый был. дискретка один из самых полезных прослушанных курсов.
Re: Кажуть, на велокиєві багато працівників ІТ-сфери?
Додано: 7.11.12 19:32
MaD_CameL
есть несколько знакомых, закончивших этот самый факультет нау, и все в один голос говорят, что учеба эта им ничего не дала. хотя нет, есть человек, закончивший этот факультет лет 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
можно попробовать регулярными выражениями
Не получилось

Кроме того, как оказалось, регекспы не предназначены для вложенных структур.
М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
Вы Боги! Читаю - наслаждаюсь

. Вот так за час взять и переделать Вселенную

! Я всегда хотел быть программистом. Но так сложилось, что работаю с людьми. По сути, реставратором. Восстанавливаю то, что создала природа, а потом оно сломалось. У меня алгоритм уже четко прописан. Степеней свободы - ноль. А вы - Творцы!