Codility zadanie 2.2 -błąd systemu?

Codility zadanie 2.2 -błąd systemu?
0

Cześć wszystkim,

mam dziwny problem z Codility z zadaniem z permutacji.
Według Codility,permutację rozumieją jako:

"A permutation is a sequence containing each element from 1 to N once, and only once."

W celu spradzenia kod przechodzi test polegający na rzuceniu tylko jednej wartości.
Czy jedna wartośc to też permutacja?

Co dziwne w moim kodzie dałem warunek:

(N to liczba elementów danej nam tablicy A[k] )
if(N==1) return 1;

...i wywaliło błąd.Oczekują dla jednej wartości zwrócenia 0.
Gdy zatem zmieniłem aby przy jednej wartości zwracało 0,okazuje się ,że też źle...Jednak oczekują 1.
O co chodzi? ;0
To jakiś bład systemu?

Treść zadania:
"
A non-empty zero-indexed array A consisting of N integers is given.
A permutation is a sequence containing each element from 1 to N once, and only once.
For example, array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
A[3] = 2
is a permutation, but array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
is not a permutation, because value 2 is missing.
The goal is to check whether array A is a permutation.
Write a function:
int solution(int A[], int N);
that, given a zero-indexed array A, returns 1 if array A is a permutation and 0 if it is not.
"

Moje rozwiazanie w C:

Kopiuj
#include <stdlib.h>

int solution(int A[], int N) {
    
    if(N<=1) return 1;
    int *tab=(int*)calloc(N,sizeof(int));
    int i;
        
    for(i=0;i<N;i++) tab[ A[i] -1 ]=1;
    for(i=0;i<N;i++) if(tab[i]==0) return 0;
    return 1;
    
} 

Dodam jeszcze ,że przy warunku " if(N==1) return 0; " twierdzą również,że tablica 100 000 wartości,każdej identycznej też powinna być permutacją,mimo ,ze w instrukcji jest napisane wyraźnie " containing each element from 1 to N once, and only once "
Bardzo prosze o pomoc.

_naf
Tablica z 1 elementem według wytycznych jest permutacją jeżeli wartość jej elementu wynosi 1. Nie sądzę, aby za każdym razem podawano takie same dane. Bardziej generowanie losowo wartości do konkretnego testu. Dla n=1 musimy rozpatrzeć dwa możliwe przypadki: A[0]=1; tutaj program powinien zwrócić 1 (zawiera wszystkie wartości z zakresu <1, n>), A[0]=2; // lub inna wartość większa od n powinno zwrócić 0.
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

Nic nie rozumiesz. Masz mieć w tej wejściowej tablicy jako WARTOŚCI kolejne liczby 1..N
Więc dla tablicy o 1 elemencie powinien on (element tablicy) wynosić 1. Dla tablicy o 2 elementach powinny mieć wartości 1 oraz 2 (kolejność dowolna). Więc nie każda 1-elementowa tablica jest poprawna. Tylko taka o elemencie równym 1.

edit: zresztą robisz tu panie jakieś cuda na kiju. Suma takiego ciągu arytmetycznego o n elementach i różnicy 1 to S=n*(n+1)/2. Więc jeśli zakresy danych na to pozwalają to ja bym po prostu przeiterował tablicę i odejmował elementy tablicy od S a na koniec sprawdził czy jest 0 czy też nie. (bzdury i majaki)
Jeśli zakresy są za duże to bym tą tablicę posortował i przeiterował sprawdzając czy wszystkie liczby są po kolei od 1 do N i jeśli trafi sie coś nie po kolei (albo zaczniemy od innej liczby niż 1) to zwrócił 0.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 7x, ostatnio: Shalom
pingwindyktator
ja bym po prostu przeiterował tablicę i odejmował elementy tablicy od S a na koniec sprawdził czy jest 0 czy też nie ?
Shalom
No oczekiwana suma jest znana więc jak suma tablicy jest inna to wejście jest złe. Masz pomysł na lepsze pesymistycznie liniowe rozwiązanie? Zliczanie wymaga dodatkowej pamięci...
pingwindyktator
Ale to co mówisz to bzdury. Ja rozumiem to tak: "permutacja" w tym zadaniu rozumiana jest jako permutacja zbioru {1, 2, ...., N}. Znamy sume elementów tego zbioru, ale ten warunek nie jest wystarczający. Przykład? {1, 1, 4}, S = 6 oraz {1, 2, 3}, S = 6. A rozwiązanie w O(n) i stałej pamięci jest dość ciekawym zadaniem, musze przeznać.
Shalom
@pingwindyktator trzeba było tak od razu, oczywiście że bredzę :D
_naf
  • Rejestracja:prawie 10 lat
  • Ostatnio:prawie 9 lat
  • Postów:87
0

@Shalom, sprawdzenie czy suma elementów tablicy = n*(n+1)/2 nie jest wystarczające.
PoC:
A = [1,2,3,3,6];
S=15, suma elementów tablicy=15, a tablica nie jest permutacją.

Ja bym zrobił to inaczej, w jednej pętli która się wykona maksymalnie n razy:

Kopiuj
bool b[n+1]=false; // jeżeli będzie miała długość n, nie obsłuży ostatniego elementu D;
for(i=0; i<n; i++){
  if(b[a[i]] || a[i]>n || a[i]<1) return 0;
  b[a[i]]=true;
} // nie musisz nic więcej robic
return 1;

tak chyba będzie bardziej najbardziej optymalne, bez liczenia jakichkolwiek sum :)

edytowany 6x, ostatnio: _naf
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

No tak, oczywiście zapomniałem o tym że mogą tam być błędne liczy a dobra suma :P @_naf ale nadal masz O(n) dodatkowej pamięci :P
Da sie to zrobić bez pamięci, korzystając tylko z wejściowej tablicy, bo ona przecież ma dokładnie tyle pamieci ile nam trzeba.
Bierzemy A[0] a następnie skaczemy sobie do elementu tablicy A[A[0]], zapamiętujemy sobie tą wartość tabllicy, zerujemy ten element i skaczemy znów do A[zapamietana_wartosc-1] i powtarzamy sobie te czynności. Jeśli skoczymy na wyzerowany element to znaczy że tablica jest niepoprawna bo dwa elementy są identyczne. Jeśli chcemy skoczyc poza tablicę to wejście nie jest poprawne bo jest tam za duża wartość gdzieś.
Niestety jest tu głupi przypadek szczególny - pozycja startowa. W tablicy są cykle więc może tak być że skoczymy na element z którego startowaliśmy (np. na 0) i wtedy musimy sobie wybrać nowy element startowy z tablicy (jakiś jeszcze nie wyzerowany).

Niestety to sprawia że pesymistycznie algorytm robi sie O(n2) przez samo to głupie szukanie nowej pozycji startowej (pesymistycznie mamy cały czas cykle po 2 kolejne elementy ;]).

Podsumowując: albo bierzemy O(n) + O(n) pamięci albo bierzemy O(nlogn) w pamięci stałej.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
pingwindyktator
Sądzę, że da się w O(N) bez dodatkowej pamięci, pracuję nad tym ;p
pingwindyktator
  • Rejestracja:ponad 12 lat
  • Ostatnio:2 miesiące
  • Lokalizacja:Kraków
  • Postów:1055
3
Kopiuj
bool solution (int *Array, size_t n) {
    for (size_t i = 0; i < n; ++i) {
        if (Array[i] < 1 || Array[i] > n)
            return false;
    }

    for (size_t i = 0; i < n; ++i) {
        if (Array[abs(Array[i]) - 1] < 0)
            return false;
        
        Array[abs(Array[i]) - 1] *= (-1);
    }
    
    for (size_t i = 0; i < n; ++i) {
        if (Array[i] > 0)
            return false;
    }
    return true;
}

@Shalom: Jestem przekonany, że to działa. W skrócie:
pętla pierwsza sprawdza, czy wszystkie liczby są z odpowiedniego zakresu.
w pętli drugiej bierzemy każdy element Array[i] i w miejscu przez niego wskazywanym - 1 zmieniamy znak liczby. To informuje nas o tym, ze liczba Array[i] wystąpiła w tablicy. Jeśli wystąpi drugi raz - pierwszy if w tej pętli to wyłapie.
w trzeciej pętli sprawdzamy, czy wszystkie liczby zostały oznaczone jako takie, które wystąpiły w tablicy. Wiemy, że jeśli coś wystąpi więcej niż raz, to zwrócimy false (pętla druga). Jeśli natomiast któraś z liczb nie wystąpi w ogóle - odpowiednie miejsce w tablicy nie będzie ujemne.

Czyli podsumowując: każda liczba Array[i] jest z odpowiedniego zakresu + każda wystąpiła dokładnie jeden raz. No i jest ich odpowiednia ilość, to oczywiste.


do not code, write prose
edytowany 3x, ostatnio: pingwindyktator
Zobacz pozostały 1 komentarz
pingwindyktator
Przecież zmieniam znak elementów tablicy, więc one będą ujemne.
pingwindyktator
Ale trzecia pętla rzeczywiście jest zbędna. W każdym razie - działa, jest O(n) i stała pamięc, jest sukces.
_naf
Ten abs naprawdę nie jest potrzebny. Wypisz sobie to lepiej przed ifem w drugiej pętli na ekranie, zobaczysz o co chodzi :P <code=c>int z = Array[Array[i] - 1]; printf("no-abs: %d \n", z); int x = Array[abs(Array[i]) - 1]; printf(" abs: %d \n", x);</code>
pingwindyktator
Nie rozumiesz. W tablicy zmieniamy znak liczby na ujemny - dla informacji. Jak zatem chcesz sie odwoływać do Array[cos_ujemnego]? http://ideone.com/YS03hG
_naf
mój błąd :) wrzuciłem to w ten sposób: http://goo.gl/Uq7voA i wyciągnąłem pochopne wnioski. Dzięki za wyjaśnienie
A7
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 6 lat
  • Postów:48
1
Kopiuj
bool is_permutation(int Arr[], int size)
{
	std::sort(Arr, Arr + size);
        if (Arr[0] != 1)
        {
              return false;
        }
	for (int i = 0; i < size; ++i)
	{
		if (i + 1 <= size)
		{//check that we will not access index out of bounds

			if (Arr[i + 1] - Arr[i] != 1)
			{//1 - 0 == 1, 2 - 1 == 1, etc
				return false;
			}
		}
	}
	return true;
}

Modern C++ version (dzieki dla @fasadin, tylko szczera krytyka pozwala nam na poprawe i udoskonalenie, thanks bro! ;) ):

Kopiuj
bool is_permutation_MC(int Arr[], int size)
{
	std::set<int> aSet{ Arr, Arr + size };
	if (*aSet.cbegin() != 1)
	{
		return false;
	}
	for (auto beg = aSet.cbegin(), end = aSet.cend(); beg != std::prev(end); ++beg)
	{
		if ((*std::next(beg) - *beg != 1))
		{//1 - 0 == 1, 2 - 1 == 1, etc
			return false;
		}
	}
	return true;
}
edytowany 2x, ostatnio: Artur77
Zobacz pozostałe 31 komentarzy
A7
@pingwindyktator No i w porzadku, ale to ma sie do pomocy OP jak udowodnienie ze szybciej mozna wejsc do domu skaczac przez okno, niz sie pie**szyc z szukaniem kluczy, otwieraniem drzwi itd. ;)
pingwindyktator
;D nie no, ja stąd ide
fasadin
POKAZ KOD! :D NIE WAZNE ZE WIESZ JAK NAPISAC. KOD!!!! btw Artur, czemu gadasz o C++ skoro tu chodzi o C? Zreszta Twoj kod z C++ (z tym nowoczesnym C++ o czym piszesz) tez ma malo wspolnego (oprocz std::sort)
A7
@fasadin "NIE WAZNE ZE WIESZ JAK NAPISAC. KOD!!!!" Z tym stwierdzeniem nie zgodzila by sie wiekszosc rekruterow. ;)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.