Nawiasowanie

0

Zrobiłem program sprawdzający poprawne nawiasowanie lecz dostaję za niego 0 pkt... gdzie może być błąd? Wydaje mi się że wszystko działa... treść zadania:

Podany jest napis składający się z nawiasów () i []. Mówimy, że napis jest poprawny, jeśli spełnia jeden z poniższych warunków:

    * jest to pusty napis,
    * jeżeli A i B są poprawne, to AB jest poprawne,
    * jeżeli A jest poprawny, to (A) i [A] są także poprawne.

Napisz program, który dla podanego napisu sprawdzi jego poprawność. Twój program może zakładać, że maksymalna długość łańcucha wynosi 128 znaków.

Dane wejściowe składają się z jednej liczby nieujemnej N podanej w pierwszym wierszu oraz sekwencji N napisów złożonych z nawiasów () i []. Każdy napis jest podany w osobnym wierszu.

Jako wynik Twój program powinien dla każdego napisu wypisać na ekranie słowo Yes, w przypadku gdy napis jest poprawny, lub słowo No gdy tak nie jest.

Przykładowe dane:

3
([])
(([()])))
([()[]()])()


Wynik:

Yes
No
Yes
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <iostream>
# include <vector>

using namespace std;

vector<char> stos;
int kwadratowe = 0;
int okragle = 0;
int a=-1;
int n=0;

int main()
{
    cin>>n;

    for(int d=0; d<n; d++)
    {
    kwadratowe = 0;
    okragle = 0;
    a=-1;

    stos.clear();
    string nawiasy;

    cin>>nawiasy;


    for(int i=0; i<nawiasy.length(); i++)
    {
        stos.push_back(nawiasy[i]);
        a++;
                if((stos[a] == ']') && (stos[a-1] == '['))
        {
            stos.pop_back();
            stos.pop_back();
            kwadratowe++;
            a--;
            a--;
        }
        if((stos[a] == ')') && (stos[a-1] == '('))
        {
            stos.pop_back();
            stos.pop_back();
            okragle++;
            a--;
            a--;
        }
    }


if((kwadratowe*2)+(okragle*2) == nawiasy.length())
{
cout<<"Yes"<<endl;
}
else
{
    cout<<"No"<<endl;
}
    }

    return 0;
}
0

np. dla "]..........."
sprawdzasz stos[-1]

0

Przemyśl to jeszcze raz. Ja bym próbował systematycznie uproszczać napis do momentu aż nie będzie to możliwe, bo napis będzie pusty (prawidłowy) lub w oczywisty sposób nieprawidłowy (nie spełnia żadnego z warunków). Jest na to naprawdę prosty sposób.

0

MarekR22: to zbytnia kombinacja.

w pętli po wszystkich znakach stringa:
{
Jeśli napotkamy (, odkładamy to na stos.
Jeśli napotkamy [, odkładamy to na stos.
Jeśli napotkamy ) to zdejmujemy ze stosu (. Jeśli jednak na stosie było cokolwiek innego niż ( to return false.
Jeśli napotkamy ] to zdejmujemy ze stosu [. Jeśli jednak na stosie było cokolwiek innego niż [ to return false.
Jeśli napotkamy cokolwiek innego, return false.
}
return true.

Żeby nie było za łatwo, gotowca mam w Pascalu ;-)

function poprawny(n:shortstring):boolean;
var stos:shortstring;
    i:integer;
const LCB='('; RCB=')';
      LSB='['; RSB=']';
begin
  poprawny:=false;
  stos:='';
  for i:=1 to length(n) do
  case n[i] of
    LCB : begin
            setlength(stos,length(stos)+1);
	    stos[length(stos)]:=LCB
          end;
    LSB : begin
            setlength(stos,length(stos)+1);
	    stos[length(stos)]:=LSB
          end;
    RCB : begin
            if length(stos)=0 then exit;
            if stos[length(stos)]=LCB
	      then setlength(stos,length(stos)-1)
	      else exit
          end;
    RSB : begin
            if length(stos)=0 then exit;
            if stos[length(stos)]=LSB
	      then setlength(stos,length(stos)-1)
	      else exit
          end
    else exit
  end;
  poprawny:=true
end;
0

można to zrobić "w miejscu",
konsumując kolejne znaki robimy sobie miejsce na stos w stringu wejściowym

sp=-1                          // pusty stos
i=0;                           //
while s[i]
    if sp<0                    // stack.empty
        sp++; s[sp]=s[i]       // stack.push (s[i])
    else
        if para(s[sp], s[i])   // czy stack.top odpowiada s[i]
            sp-=1              // stck.pop
        else
            sp++; s[sp]=s[i]   // stack.push (s[i])
    i++
return sp<0                    // ok jeżeli stos jest pusty

można zmienić wiersze push "sp++;s[sp]=s[i]"
na 
    sp++;
    if s[i]=='['
        s[sp]=']'
    else
        s[sp]=')'
dzięki czemu można uprościć porównanie wieżchołka z bieżącym,
zamiast  "if para(s[sp], s[i])" może być "if s[sp]==s[i]"

wg pomysłu Azariena, można do push dodać sprawdzenie czy s[i] jest równe ')' lub ']'
dzięki czemu szybciej możemy odpowiedzieć, że nie jest OK
</cpp>
0
Azarien napisał(a)

MarekR22: to zbytnia kombinacja.

Jaka zbytnia kombinacja, cały czas usuwasz ze napisu napisy "()" i "[]" tak długo jak to jest możliwe, jeśli na końcu otrzyma się pusty napis to znaczy, że napis początkowy był prawidłowy, w jeśli napis jest niepusty to znaczy, że był nieprawidłowy. To jest o niebo prostsze niż kombinowanie ze stosem.

0
MarekR22 napisał(a)

To jest o niebo prostsze niż kombinowanie ze stosem.

Chcesz się ścigać? Proponuję dla stringa długości miliarda znaków. Przegrasz.

0

wiem, że twoje rozwiązane jest szybsze (optymalne), ale ja mam na myśli zrozumienie algorytmu przez początkującego. Moje rozwiązanie dosłownie korzysta z treści zadania.

0

Szybkie, uniwersalne i 4x krótsze niż pascalowa wersja:

  val brackets = Map(')' -> '(', ']' -> '[')

  def check(s: Seq[Char]): Boolean = ckeck(Stack(), s)

  def check(stack: Stack[Char], s: Seq[Char]): Boolean =
    s match {      
      case Seq(b, rest @ _*) if brackets.values.toList.contains(b) =>
        check(stack push b, rest)      
      case Seq(b, rest @ _*) if brackets.contains(b) =>
        !stack.isEmpty && stack.top == brackets(b) && check(stack.pop, rest)      
      case Seq() =>
        stack.isEmpty
    }

BTW: no i bez ani jednej zmiennej :D

0

Wszystko ok... rozumiem... stosowałem sposób z usuwaniem znaków () i [] ze stosu po wczesniejszym wlozeniu ich na niego... lecz nadal mam źle? mógłby ktoś podać jakiś przykład dla którego zwracane są złe dane w moim programie?

0
Zioooooomus napisał(a)

Wszystko ok... rozumiem... stosowałem sposób z usuwaniem znaków () i [] ze stosu po wczesniejszym wlozeniu ich na niego... lecz nadal mam źle? mógłby ktoś podać jakiś przykład dla którego zwracane są złe dane w moim programie?
eeeee......., ALBO rozwiązanie ze stosem, ALBO rozwiązanie z usuwaniem "()", "[]". To dwa zupełnie różne podejścia.
usuwanie ciągów znaku korzysta z reguły:
jeśli A jest prawidłowe to "(A)" i "[A]" też są prawidłowe, więc usuwając z CIĄGU znaków podciągi "()", "[]" poprawność ciągu pozostaje ta sama.

W przypadku stosu analizujesz kolejne znaki ciągu, jeśli napotykasz nawias otwierający to kładziesz go na stosie, jeśli natrafiasz na nawias zamykających to sprawdzasz czy stos jest pusty, jeśli nie to ściągasz element ze stosu i sprawdzasz, czy typ ściągniętego nawiasu odpowiada badanemu nawiasowi zamykającemu.

0

Wszystko rozumiem... przeanalizuj sobie moj program... działa on częściowo jak stos... a po kompilacji daje prowidłowe wyniki... więc gdzie błąd?

0

Już łącze się z tobą telepatycznie, bo nie widzę nowego kodu.
Widać tylko twoją pierwszą wersję, która nie trzyma się kupy.

0

Nadmienię, że sposób z usuwaniem znaków ma złożoność O(n^2), a sposób ze stosem O(n).
A co do poprawności - na pewno sprawdziłeś wszelkie przypadki brzegowe?

Np takie:

""
"("
"(()"
"())"
")"
"()"
"()()"
"()("
"[()]"
"([)]"
"[(])"
"]["

0
Krolik napisał(a)

Nadmienię, że sposób z usuwaniem znaków ma złożoność O(n^2), a sposób ze stosem O(n).
A co do poprawności - na pewno sprawdziłeś wszelkie przypadki brzegowe?

Np takie:

""
"("
"(()"
"())"
")"
"()"
"()()"
"()("
"[()]"
"([)]"
"[(])"
"]["

Jedyne co z tych przykładów mi nie działa to przykład z pustym nawiasem... (dodalem wyjątek i powinno być ok... no ale nie jest :] )

0

Azarien dał ci kod w Pascalu, a tej język jest na tyle podobny do C, że naprawdę dziwię się, że jeszcze nie masz dobrze tego zrobionego.

0
Krolik napisał(a)

A co do poprawności - na pewno sprawdziłeś wszelkie przypadki brzegowe?

Np takie:

""

A ja mam pytanie.
Jak zrobić, gdy nic nie podam w sensie podam pusty wiersz i chcę by mi zwróciło true.

OK już wiem

	if (dlugosc==0) {
		cout << "Yes" << endl;
	}	

gdzie dlugosc jest wielkoscia tablicy do jakiej wczytuje dane.

1 użytkowników online, w tym zalogowanych: 0, gości: 1