Ananagramy z podanego zbioru słów

0

Witam. Mam do napisania program wypisujący ananagramy z podanego zboru słów. Ananagram to wyraz, w którym nie da się tak zmienić kolejności liter aby uzyskać nowe słowo. Takie przeciwienstwo do anagramu. Program nie moze potrafic okreslic czy przestawione litery tworza poprawne slowo dlatego na wejsciu podajemu slownik (czyli wspomniany zbior wyrazow).

Przykladowo jak na wejsciu podamy zbior slow:

abc, cba, def, gHi, hGi

to program na wyjsciu ma wyswietlic slowo:
def

gdyż jest to ananagram w tym zbiorze, a pary abc i cba oraz gHi i hGi sa anagramami.

Wielkosc liter nie ma znaczenia!

Napisalem program wczytujacy zbior wyrazow do tablicy. Tworze kopie tej tablicy.

Wszystkie litery w wyrazach wejsciowych zamieniam na wielkie i sortuje je.

Tylko teraz nie wiem jak przeszukac te zbiory i znalezc ananagramy. Myslalem o uzyciu stlowej funkcji nex_permutation ale nie wiem czy to dobry sposob.

#include <iostream>
#include <string>
#include <algorithm>
#include <stdio.h>

using namespace std;

int main()
{
string wejscie[1000];
string wynik[1000];
string kopia[1000];
int i=0;
cin >> wejscie[i];
kopia[i]=wejscie[i];

//zadawanie wyrazow
while (wejscie[i][0] != '#')
{
    i++;
    cin >> wejscie[i];
    kopia[i]=wejscie[i];
}


//sortowanie liter w kazdym wyrazie
for (int j=0; j<i; j++)
{
    sort(wejscie[j].begin(), wejscie[j].end());
}

//zamiana wszystkich liter na duze w wyrazach wejsciowych
for (int x=0; x<i; x++)
{
    transform(wejscie[x].begin(), wejscie[x].end(), wejscie[x].begin(), ::toupper);
}




cout << endl;

//wypisanie wszystkich wyrazow skopiowanych
for(int j=0; j<i; j++)
{
    cout << kopia[j]<<  endl;
}

cout << endl;

//wypisanie wszystkich wyrazow wejsciowych po zmianie wielkosci liter
for(int j=0; j<i; j++)
{
    cout << wejscie[j]<<  endl;
}


return 0;
}
 
0

a nie łatwiej zliczyć ilości liter i na tej podstawie stwierdzić czy wyraz może lub nie może być anagramem? (sprawdzić czy w ogóle może nim być). można też pogrupować wyrazy na długości, bo żeby wyraz mógł być anagramem innego musi mieć tą samą długość. (chyba, że coś źle zrozumiałem)

0
krwq napisał(a)

a nie łatwiej zliczyć ilości liter i na tej podstawie stwierdzić czy wyraz może lub nie może być anagramem? (sprawdzić czy w ogóle może nim być). można też pogrupować wyrazy na długości, bo żeby wyraz mógł być anagramem innego musi mieć tą samą długość. (chyba, że coś źle zrozumiałem)

Może i łatwiej, ale nie wpadło mi to wcześniej dogłowy.
Postanowiałem posortować wyrazy i litery w zbiorze i sprawdzić, czy sąsiednie się różnia. Jeśli tak to powinny być ananagramimi. Ale nie działa do końca.

#include <iostream>
#include <string>
#include <algorithm>
#include <stdio.h>

using namespace std;

int main()
{
string wejscie[1000];
string kopia[1000];
string temp;
string temp2;
int i=0;

cin >> wejscie[i];
kopia[i]=wejscie[i];

//zadawanie wyrazow
while (wejscie[i][0] != '#')
{
    i++;
    cin >> wejscie[i];
    kopia[i]=wejscie[i];
}


//sortowanie liter w kazdym wyrazie
for (int j=0; j<i; j++)
{
    sort(wejscie[j].begin(), wejscie[j].end());
}

//sortowanie wyrazow wejsciowych

for (int k = 0; k<i; k++)
                for (int j=0; j<i-1; j++)
                        {
                                if (wejscie[j] > wejscie[j+1])
                                {
                                        temp = wejscie[j+1];
                                        wejscie[j+1] = wejscie[j];
                                        wejscie[j] = temp;
                                }
                        }

// sortowanie skopiowanych wyrazow
for (int k = 0; k<i; k++)
                for (int j=0; j<i-1; j++)
                        {
                                if (kopia[j] > kopia[j+1])
                                {
                                        temp2 = kopia[j+1];
                                        kopia[j+1] = kopia[j];
                                        kopia[j] = temp2;
                                }
                        }

//zamiana wszystkich liter na duze w wyrazach wejsciowych
for (int x=0; x<i; x++)
{
    transform(wejscie[x].begin(), wejscie[x].end(), wejscie[x].begin(), ::toupper);
}

cout << endl;

for(int j=0; j<i-1; j++)
{
    if(wejscie[j] != wejscie[j+1])
    cout << kopia[j+1]<< endl;
}



return 0;
}
 
1

A nie prościej wczytać poszczególne zbiory liter do tablicy stringów, posortować te stringi i porównywać każdy string z kolejnymi w tablicy, jeżeli są takie same, to oznaczyć obydwa jako anagramy? Dla twojego przykładu:
abc, cba, def, gHi, hGi
sprawdzasz abc z posortowanymi cba, def, gHi, hGi;
cba z def,
def z gHi, hGi;
itd. Sprawdzanie, czy stringi są takie same jest bardzo proste:

 #include <iostream>
#include <string>
#define usi unsigned short int
using namespace std;
int main() {
	string a, b;
	cin >> a >> b;
	if (a==b) cout << "TU\n";
	else
	if (a<b) cout << "WCZESNIEJ\n";
	else
	if (a>b) cout << "DALEJ\n";
}

ewentualnie funkcja

strcmp ( const char * str1, const char * str2 );

.
Ale jeżeli chcesz to mieć w tablicy, to możesz użyć podobnej funkcji:

memcmp ( const void * ptr1, const void * ptr2, size_t num );
1
int cmp(char * a, char * b){ 
	return *a - *b;}
	
main(){
	char t[100][20]; 
	char a[100][20];
	char s     [20];
	int  n=0, i;
	while( 0 < scanf("%s", s) ){
		for( i=0; 0<s[i]; i++ ) 
			t[n][i]= tolower(s[i]);
		t[n][i]=0; 
		qsort(t[n], strlen(s), 1, cmp); 
		strcpy(a[n], s);
		for( i=0; strcmp(t[i], t[n]); i++ ) 
			;
		if( i < n ) { a[n][0]=0; a[i][0]=0; }
		else n++; }
	for( i=0; i<n; i++)
		puts(a[i]); }

http://ideone.com/oJSDd

O(n^2) bo proste liniowe szukanie

1

Ja bym zaczął od wymyślenia jakiegoś sprytnego hash-a. Coś w stylu:
((Liczba unikatowych liter * c + id litery najczęstszej lub pierwszej leksykalnie) * c + id następnej takiej litery) * c + id następnej takiej litery
gdzie c to dopuszczalna liczba rożnych liter.
równość hashy to warunek koniczny, by dwa wyrazy były anagramami, więc wstępnie można szybko pogrupować wyrazy, a potem sprawdzać warunek wystarczający w ramach każdej grupy.

0

Wczytałem do tablicy stringow, gdzie kolejno zmienilem wszystkie litery na male, posortowalem litery, nastepnie kazdy taki ciag znakow porownywalem z pozostalymi. Jesli byl jakis unikalny to w tablicy intow przypisywalem dla tego elementu 1. Potem odpowiednie elementy z pierwotnej tablicy wyrazow posortowalem i wypisalem.

Wasze wypowiedzi okazaly sie bardzo pomocne.

Leca plusiki. dziekuje i pozdrawiam.

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