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
Shalom
O(nlogn) i to niezbyt wyszukany :P
A7
@Shalom, poprawny, latwy do czytania i odpowiednio szybki. Na pewno lepszy od tego co ty proponowales.
Shalom
? Przecież już w moim pierwszym poscie wspomniałem o tym że można to sortować. Tylko że codility często podaje oczekiwaną złożoność obliczeniową i jeśli należało zrobić to w O(n) (co jest możliwe, więc to wysoce prawdopodobne) to twoje rozwiązanie zwyczajnie dostałoby 0 punktów. Autor nie pokusił się w podanie takiej informacji więc spekulowalśmy o rozwiązaniu optymalnym. Twoje rozwiązanie jest ok, ale jest też najbardziej oczywistym rozwiązaniem więc bardzo możliwe że nie można by go użyć.
A7
@Shalom To mogles podac kod, zamiast tylko "wspominac". I zamiast podejrzewac co Codility chcialo (czego autor nie wspomnial) nastepnym razem najpierw staraj sie podac poprawna odpowiedz. Bo takie sa kroki: Kod musi byc: 1) Poprawny 2) Czytelny 3) Szybki W takiej kolejnosci. I moj kod jest dokladnie taki. Nie mozna tego powiedziec o Twoim "wspominaniu" i "spekulowaniu". ;P
A7
@Shalom O, i jeszcze jedno, za taka logike: "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..." Nie tylko dalbym Ci zero punktow ale tez podziekowal bym Ci za rozmowe i zyczyl szczescia w McDonaldzie.;P
Shalom
@Artur77 nie no bez żartów. Przecież wersja z sortowaniem jest oczywista. A ta twoja zresztą jest idiotyczna tak BTW. Mogłeś po ludzku zrobić pętlę do size-1 i nie kombinować z jakimś śmiesznym warunkiem ;] No i oczywiście twój kod jest błędny bo wcale nie sprawdza czy wartości są poprawne, tylko czy są po kolei. Jak wrzuce ci na wejście tablicę [10,11,12] to zwróci mi true. Więc z twoich 3 kryteriów twój kod nie jest ani poprawny (patrz: mój kontrprzykład), ani szybki (bo O(nlogn) a nie O(n)). A dodatkowy if policzyłbym jako obniżenie czytelności kodu, bo dało sie prosciej
Shalom
@Artur77 dobrze że statki kosmiczne i akceleratory cząstek są łatwiejsze niż obsługa w mcdonalds ;) Zauważ ze ja przynajmniej spróbowałem chwilę pomyśleć nad jakimś ciekawszym rozwiązaniem zadania. Ty poleciałeś na łatwiznę z brutem i jeszcze go spieprzyłeś... ;]
A7
@Shalom, prawda, mowia o tym ze permutacja ma zaczynac sie od 1. Przyznaje, tego nie wzialem pod uwage. Latwo poprawic. Dac warunek czy pierwszy element to 1. A jak mowisz ze da sie prosciej? Pewnie, zawsze da sie prosciej. Pokaz kod.
A7
@Shalom No i jakie rozwiazanie dales? Low level po tablicach? Kto tak teraz uzywa C++? Grebosz i spolka?
Shalom
o_O Piłeś? Nie pisz. Jakie rozwiązanie? O czym ty mówisz? Nie ma tu przecież ani jednej linijki mojego kodu. Jest za to twój, który nie dość że nie działa poprawnie, jest nieoptymalny i jest napisany mało czytelnie to jeszcze jest napisany w innym języku niż ten o który pytał autor. Kumulacja jakaś :D A co do pana Grębosza to nie bardzo rozumiem jaki masz z nim problem. Znasz faceta? Mam znajomych z IFJ PAN którzy z nim pracowali i raczej chwalili go jako całkiem dobrego...
A7
@Shalom "Nie ma tu przecież ani jednej linijki mojego kodu." Dokladnie. Jak mowisz ze da sie prosciej, bardziej optymalnie itd to pokaz kod zamiast tylko wspominac i spekulowac ;P Nowoczesny kod a nie kod z tablicami i wskaznikami. Do pana Grebosza nie mam nic osobiscie. Ale jego styl jest staromodny i nikt tak nie powinien C++ uzywac w 2015.
Shalom
@Artur77 autor pytał o język C. Módl sie żeby cię przez tego skajpa rekrutowali a nie przez codility bo może być słabo jak wyślesz niedziałające rozwiązanie, napisane nieoptymalnie, średnio czytelnie i jeszcze w złym języku... :D
A7
@Shalom podaj kod zamiast dodawac smieszne i zlosliwe uwagi jak mala rozkapryszona dziewczynka.
Shalom
Ale po co? Autor wcale nie prosił o kod tylko o wyjaśnienie czemu jego rozwiązanie nie działa. Ale spoko, nie doczytałeś w jakim języku to pewnie problemu autora też nie doczytałeś. Czytałeś w ogóle ten pierwszy post? Musiałeś się za to pochwalić niedziałającym kodem :D Wystarczająco dużo kodu piszę w pracy, nie widzę sensu bez potrzeby (bo autor wcale nie pytał) produkować trywialnych kodów w niedzielne popołudnie ;]
A7
@Shalom, i znowu, tylko gadka a kodu jak nie bylo tak nie ma. Mistrzunio. ;] BTW, moj kod (poprawiony) dziala dokladnie tak jak ma dzialac.
pingwindyktator
@Artur77 działa w O(nlogn) czasie i O(n) pamięci, więc srednio fajnie.
Shalom
@pingwindyktator nie narzekaj, teraz po poprawce przynajmniej w ogóle działa :P no i nie wymagaj od niego żeby wiedział co siedzi pod spodem std::sort i jaką ma zlożoność :P a tego indeksu pętli nadal nie poprawił tylko robi magicznego ifa :D
A7
@pingwindyktator i tak lepiej niz ten kod ktory @shalom (nie)zaprezentowal ;)
pingwindyktator
No halo, osobiście podoba mi sie algorytm @Shalom, wykorzystuje rozkład permutacji na cykle (nie oczekuję zrozumienia) i działa w średnim czasie O(n) i stałej pamięci,
A7
@shalom a Ty kazdy kod ktory piszesz to bezblednie od pierwszego razu chodzi? Wiadomo, mistrzunio ;] A kodu jak nie bylo tak nie ma ;) ;) ;)
A7
@shalom i znowu spekulacje? Wiem co siedzi pod spodem sort ale takiego kodu, (low level) nie powinno sie uzywac na codzien. Przestan spekulowac, wspominac itd. Pokaz kod.
A7
@pingwindyktator mi tez sie pewnie spodoba, ale najpierw musze go zobaczyc.
twonek
@fasadin popcorn bierz
Shalom
@Artur77 jak już się chwalę gdzieś kodem publicznie to zwykle działa ;) Ale ja wiem że ludzie często bezmyślnie kopiują kody albo jak widzą kod to nie czytają reszty posta, więc generalnie wolę opisać algorytm niż podawać gotową implementacje. Bo wtedy czytelnikowi coś w głowie zostanie. @pingwindyktator no mój rozkład na cykle w sumie jest bardzo podobny do twojego algorytmu, tylko że ty dość sprytnie ominąłeś mój problem z szukaniem pozycji startowej bo nie łazisz po całym grafie tylko po parach ;]
A7
@Shalom i znowu ta sama stara spiewka i spekulacje. A kodu jak nie bylo tak nie ma. Stara spiewka, bo nie ma kodu, a spekulacje bo mowisz ze ja sie chcialem pochwalic co jest bledne. Ja po prostu chcialem pomoc.
pingwindyktator
Ja się tylko zastanawiam po co ten if, bo może to ja nie rozumiem ;p
A7
@pingwindyktator nie atakuje Cie, ale Twoj kod w porownaniu do mojego jest duzo mniej czytelny. Moze szybszy, to powinno sie sprawdzic, ale jesli chodzi o kod, ktory powinien znalezc sie w source, moj raczej powinien byc przyjety a nie Twoj ze wzgledu na nieczytelnosc. Zwlaszcza ze sam nie jestes pewien ze Twoj kod dziala i generalnie ciezko na pierwszy rzut oka sie do tego przekonac.
Shalom
@Artur77 Masz mnie! Ja po prostu nie umiem programować. A tutaj na forum tylko sobie tak trolluje :D Dobrze przynajmniej że nikt w pracy (ani aktualnej ani poprzednich) się nie zorientował :) Dobrze że chciałeś pomóc, chwali się! Nie obrażaj sie od razu za taki mały trolling :P
Shalom
@pingwindyktator if jest dlatego że kolega Artur nie wie że można zrobić pętlę do size-1 zamiast do size ;)
A7
@Shalom nic sie nie obrazam i podejrzewam ze jestes OK kolesiem. Chcialem po prostu wyjasnic moje motywy. To wszystko. A kodu jak nie bylo tak nie ma ;)
pingwindyktator
Zwlaszcza ze sam nie jestes pewien ze Twoj kod dziala a to ciekawe. A mój kod pojawił się dlatego, ze najzwyczajniej z @Shalom spekulowaliśmy, czy rozwiązanie tak szybkie jest możliwe. No i jest to ciekawy problem. Był.
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.