JavaRush /Blog Java /Random-PL /O co pytają na rozmowie kwalifikacyjnej: przegląd algoryt...

O co pytają na rozmowie kwalifikacyjnej: przegląd algorytmów, część 1

Opublikowano w grupie Random-PL
Dzień dobry wszystkim! Różne typy algorytmów wykorzystywane są w projektach częściej niż mogłoby się wydawać. Musimy na przykład posortować niektóre dane według określonych parametrów (kolumn), abyśmy mogli bez większego wysiłku się po nich poruszać. Nie ma więc nic dziwnego w tym, że podczas rozmów kwalifikacyjnych można ich zapytać o taki czy inny podstawowy algorytm i być może otrzymać zadanie jego wdrożenia za pomocą kodu. O co pytają na rozmowie kwalifikacyjnej: przegląd algorytmów, część 1 - 1A skoro jesteś na tej stronie, zaryzykuję przypuszczenie, że piszesz w Javie. Dlatego dzisiaj zapraszam Cię do zapoznania się z kilkoma podstawowymi algorytmami i konkretnymi przykładami ich implementacji w Javie. Przez niektóre mam na myśli:
  1. Przegląd algorytmów sortowania tablic:
    • sortowanie bąbelkowe,
    • sortowanie przez wybór,
    • sortowanie przez wstawianie,
    • sortowanie skorupowe,
    • szybkie sortowanie,
    • sortowanie przez scalanie.
  2. Chciwy algorytm.
  3. Algorytmy wyszukiwania ścieżki:
    • czołgając się głęboko
    • szeroki spacer.
  4. Algorytm transportu to algorytm Dijkstry.
Cóż, bez zbędnych ceregieli, przejdźmy do rzeczy.

1. Przegląd algorytmów sortowania

Sortowanie bąbelkowe

Algorytm sortowania znany jest przede wszystkim ze swojej prostoty, ale charakteryzuje się także jedną z najniższych szybkości wykonywania. Jako przykład rozważ sortowanie bąbelkowe dla liczb w kolejności rosnącej. Wyobraźmy sobie łańcuch losowo rozmieszczonych liczb, dla którego zostaną wykonane następujące kroki, zaczynając od początku łańcucha:
  • porównać dwie liczby;
  • jeśli liczba po lewej stronie jest większa, zamień je;
  • przesuń się o jedną pozycję w prawo.
Po przejściu całego łańcucha i wykonaniu tych kroków odkryjemy, że największa liczba znajduje się na końcu naszego ciągu liczb. Następnie wykonuje się dokładnie takie samo przejście wzdłuż łańcucha, postępując zgodnie z krokami opisanymi powyżej. Ale tym razem nie uwzględnimy ostatniego elementu listy, bo jest największy i już jest na ostatnim miejscu, tak jak powinno. Ponownie otrzymamy ostatni element na końcu naszego ciągu liczbowego. W związku z tym dwie największe liczby będą już na swoich miejscach. I ponownie rozpoczyna się przejście wzdłuż łańcucha, z wyłączeniem elementów, które są już na miejscu, aż wszystkie elementy znajdą się w wymaganej kolejności. Przyjrzyjmy się implementacji sortowania bąbelkowego w kodzie Java:
public class Solution {
   public static void main(String[] args) {
    int[] testArr = new int[]{6,3,8,2,6,9,4,11,1};
    bubbleSort(testArr);
       for (int i : testArr) {
           System.out.println(i);
       }
   }

   public static void  bubbleSort(int[] array) {
       for(int i = array.length -1; i > 1; i--) {
         for (int j = 0; j < i; j++) { //
             if (array[j] > array[j+1]) {
                 int temp = array[j];
                 array[j] = array[j+1];
                 array[j+1] = temp;
             }
         }
       }
   }
}
Jak widać nie ma tu nic skomplikowanego i wszystko wydaje się być super, gdyby nie jedno „ale”... Sortowanie bąbelkowe jest bardzo, bardzo powolne, ze złożonością czasową O (N²) , ponieważ zagnieżdżiliśmy się pętle. Zewnętrzne przejście przez elementy odbywa się N razy, wewnętrzne również N razy i w efekcie otrzymujemy N*N iteracji N².Ten rodzaj sortowania możesz przestudiować bardziej szczegółowo w tym artykule .

Sortowanie według wyboru

Algorytm ten jest podobny do sortowania bąbelkowego, ale działa nieco szybciej. Ponownie, jako przykład, weźmy serię liczb, które chcemy ułożyć w porządku rosnącym. Istota algorytmu polega na tym, aby po kolei przejść przez wszystkie liczby i wybrać najmniejszy element, który bierzemy i zamieniamy miejscami z elementem skrajnie lewym (element 0). Mamy tu sytuację podobną do sortowania bąbelkowego, jednak w tym przypadku posortowanym elementem będzie najmniejszy element. Dlatego kolejne przejście przez elementy rozpocznie się od elementu o indeksie 1. Ponownie te przejścia będą powtarzane, aż wszystkie elementy zostaną posortowane. Implementacja w Javie:
public class Solution {
   public static void main(String[] args) {
       int[] testArr = new int[]{6, 3, 8, 2, 6, 9, 4, 11, 1};
       sortBySelect(testArr);
       for (int i : testArr) {
           System.out.println(i);
       }
   }

   public static void sortBySelect(int[] array) {

       for (int i = 0; i < array.length-1; i++) { // внешний обычный  цикл
           int min = i;

           for (int j = i + 1; j < array.length; j++) { // обычный цикл, но с отчетом с сортированных чисел
               if (array[j] < array[min]) {
                   min = j;
               }
           }
           int temp = array[i];     // вставка отссортиованного числа, в положеную ему ячейку
           array[i] = array[min];
           array[min] = temp;
       }
   }
}
Algorytm ten jest lepszy od sortowania bąbelkowego, ponieważ tutaj liczba niezbędnych permutacji zostaje zmniejszona z O(N²) do O(N): nie przesuwamy jednego elementu przez całą listę, ale mimo to liczba porównań pozostaje O(N²) ) . Osobom chcącym dowiedzieć się więcej na temat tego algorytmu polecam ten materiał .

Sortowanie przez wstawianie

Jeszcze raz jako przykład weźmy serię liczb, które chcemy ułożyć w kolejności rosnącej. Algorytm ten polega na umieszczeniu znacznika, po lewej stronie którego elementy będą już częściowo posortowane między sobą. Na każdym etapie algorytmu zostanie wybrany jeden z elementów i umieszczony w żądanej pozycji w już posortowanej sekwencji. Zatem posortowana część będzie rosła, dopóki nie zostaną sprawdzone wszystkie elementy. Możesz zapytać: gdzie mogę dostać tę część elementów, która jest już posortowana i po której trzeba umieścić znacznik? Ale tablica pierwszego elementu jest już posortowana, prawda? O co pytają na rozmowie kwalifikacyjnej: przegląd algorytmów, część 1 - 2Przyjrzyjmy się implementacji w Javie:
public class Solution {
   public static void main(String[] args) {
       int[] testArr = new int[]{6, 3, 8, 8, 6, 9, 4, 11, 1};
       insertionSort(testArr);
       for (int i : testArr) {
           System.out.println(i);
       }
   }

   public static void insertionSort(int[] array) {

       for (int i = 1; i < array.length; i++) { // i - разделяющий маркер
           int temp = array[i]; // делаем копию помеченного element
           int j = i;
           while (j 	> 0 && array[j - 1] >= temp) { // пока не будет найден меньший элемент
               array[j] = array[j - 1]; // сдвигаем элементы вправо
               --j;
           }
           array[j] = temp;   // вставляем отмеченный элемент, в положеное ему место
       }
   }
}
Ten rodzaj sortowania jest lepszy od opisanych powyżej, ponieważ pomimo tego, że czas działania jest taki sam - O(N²) , algorytm ten działa dwa razy szybciej niż sortowanie bąbelkowe i nieco szybciej niż sortowanie przez selekcję. Przeczytaj więcej tutaj .

Sortowanie powłoki

Sortowanie to ze swej natury jest zmodyfikowanym sortowaniem przez wstawianie. O czym mówię? Chodźmy po kolei. Wybrany zostaje krok i istnieje wiele podejść do tego wyboru. Nie będziemy zagłębiać się w tę kwestię zbyt szczegółowo. Podzielmy naszą tablicę na pół i uzyskajmy określoną liczbę - to będzie nasz krok. Jeśli więc mamy 9 elementów w tablicy, nasz krok będzie wynosił 9/2 = 4,5 . Odrzucamy część ułamkową i otrzymujemy 4 , ponieważ indeksy tablicy są tylko liczbami całkowitymi. W tym kroku utworzymy połączenia dla naszych grup. Jeśli element ma indeks 0, to indeks następnego elementu w jego grupie wynosi 0+4 , czyli 4 . Trzeci element będzie miał indeks 4+4 , czwarty będzie miał indeks 8+4 i tak dalej. W przypadku drugiej grupy pierwszym elementem będzie 1,5,9…. W trzeciej i czwartej grupie sytuacja będzie dokładnie taka sama. W rezultacie z tablicy liczb {6,3,8,8,6,9,4,11,1} otrzymujemy cztery grupy: I - {6,6,1} II - {3,9} III - {8, 4} IV - {8,11} Zachowują swoje miejsca w ogólnym szeregu, ale dla nas są oznaczani jako członkowie tej samej grupy: { 6 , 3 , 8 , 8 , 6 , 9 , 4 , 11 , 1 } Dalej w obrębie tych grup następuje opisane powyżej sortowanie przez wstawianie , po którym grupy będą wyglądać następująco: I - {1,6,6} II - {3,9} III - {4,8} IV - {8 ,11} W tablicy ogólnej komórki zajmowane przez grupy pozostaną takie same, ale kolejność w nich ulegnie zmianie, zgodnie z kolejnością grup powyżej: { 1 , 3 , 4 , 8 , 6 , 9 , 8 , 11 , 6 } Tablica jest trochę bardziej uporządkowana, prawda? Następny krok zostanie podzielony przez 2: 4/2 = 2 Mamy dwie grupy: I - {1,4,6,8,6} II - {3,8,9,11} B tablica ogólna: { 1 , 3 , 4 , 8 , 6 , 9 , 8 , 11 , 6 } Przechodzimy przez obie grupy korzystając z algorytmu sortowania przez wstawianie i otrzymujemy tablicę: { 1 , 3 , 4 , 8 , 6 , 9 , 6 , 11 , 8} Teraz nasza tablica jest prawie posortowana. Pozostaje ostatnia iteracja algorytmu: dzielimy krok przez 2: 2/2 = 1. Otrzymujemy grupę, całą tablicę: { 1 , 3 , 4 , 8 , 6 , 9 , 6 , 11 , 8 } By które przechodzimy przez algorytm sortowania przez wstawianie i otrzymujemy: { 1 , 3 , 4 , 6 , 6 , 8 , 8 , 9 , 11 } Zobaczmy, jak możemy wyświetlić to sortowanie w kodzie Java:
public class Solution {
   public static void main(String[] args) {
       int[] testArr = new int[]{6, 3, 8, 8, 6, 9, 4, 11, 1};
       sortBySelect(testArr);
       for (int i : testArr) {
           System.out.println(i);
       }
   }

   public static void sortBySelect(int[] array) {
       int length = array.length;
       int step = length / 2;
       while (step > 0) {
           for (int numberOfGroup = 0; numberOfGroup < length - step; numberOfGroup++) {// проходим по всем нашим группам
              int j = numberOfGroup;
               while (j >= 0 && array[j] > array[j + step]) {//sortowanie вставкой внутри группы
                   int temp = array[j];
                   array[j] = array[j + step];
                   array[j + step] = temp;
                   j--;
               }
           }
           step = step / 2; // уменьшаем наш шаг
       }
   }
}
W tej chwili skuteczność sortowania metodą Shell nie jest w pełni uzasadniona, ponieważ wyniki różnią się w różnych sytuacjach. Szacunki uzyskane z eksperymentów wahają się od O(N 3/2 ) do O(N 7/6 ) .

Szybkie sortowanie

Jest to jeden z najpopularniejszych algorytmów, dlatego warto zwrócić na niego szczególną uwagę. Istota tego algorytmu polega na tym, że z listy elementów wybierany jest element przestawny – w zasadzie dowolny element, względem którego należy posortować pozostałe wartości. Wartości mniejsze niż po lewej stronie, wartości większe niż po prawej stronie. Następnie element podporowy wybiera również prawą i lewą część i dzieje się to samo: wartości są sortowane względem tych elementów, następnie z powstałych części wybierane są elementy podporowe – i tak dalej, aż otrzymamy posortowany wiersz. Ten algorytm w Javie jest zaimplementowany przy użyciu rekurencji:
public class Solution {
   public static void main(String[] args) {
       int[] testArr = new int[]{6, 3, 8, 8, 6, 9, 4, 11, 1};
       fastSort(testArr);
       for (int i : testArr) {
           System.out.println(i);
       }
   }

   public static void fastSort(int[] array) {
       recursionFastSort(array, 0, array.length - 1);
   }


   public static void recursionFastSort(int[] array, int min, int max) {
       if (array.length == 0)// stan выхода из рекурсии,  если длина массива равна 0
           return;

       if (min >= max) //выходим, так Jak нечего уже делить
           return;


       int middle = min + (max - min) / 2;  // выбираем середину
       int middleElement = array[middle];


       int i = min, j = max;
       while (i <= j) {  // относительно element middle определяемменьшие элементы слева, большие справа
           while (array[i] < middleElement) {
               i++;
           }
           while (array[j] > middleElement) {
               j--;
           }

           if (i <= j) {      //меняем местами
               int temp = array[i];
               array[i] = array[j];
               array[j] = temp;
               i++;
               j--;
           }
       }

       if (min < j) // запускаем рекурсию с elementми меньшими чем middle
           recursionFastSort(array, min, j);

       if (max > i)// запускаем рекурсию с elementми большими чем middle
           recursionFastSort(array, i, max);
   }
}
Bez wątpienia algorytm szybkiego sortowania jest uważany za najpopularniejszy, ponieważ w większości sytuacji działa szybciej niż inne, w czasie O(N*logN) .

Sortowanie przez scalanie

To sortowanie jest również popularne. Odnosi się do jednego z typów algorytmów, które działają na zasadzie „dziel i zwyciężaj”: w nich najpierw dzielimy zadania na minimalne części ( szybkie sortowanie jest również przedstawicielem takich algorytmów ). Jaka jest zatem istota tego algorytmu?O co pytają na rozmowie kwalifikacyjnej: przegląd algorytmów, część 1 - 3

Dzielić:

Tablica jest podzielona na dwie części o mniej więcej tej samej wielkości, każda z tych dwóch części jest podzielona na dwie kolejne i tak dalej, aż pozostaną najmniejsze niepodzielne części. Części najmniej niepodzielne mają miejsce, gdy każda tablica ma jeden element, co oznacza, że ​​taka tablica jest automatycznie uznawana za posortowaną.

Podbić:

W tym miejscu rozpoczyna się proces, który nadaje nazwę algorytmowi – łączenie . Aby to zrobić, weź dwie wynikowe uporządkowane tablice i połącz je w jedną. W tym przypadku do wynikowej tablicy zapisywany jest najmniejszy z pierwszych elementów obu tablic i operacja ta jest powtarzana, aż w obu tablicach nie będzie już więcej elementów. Oznacza to, że jeśli mamy dwie minimalne tablice {6} i {4} , ich wartości zostaną porównane i wynik zostanie zapisany: {4,6} . Jeśli istnieją posortowane tablice {4,6} i {2,8} , to najpierw porównana zostanie wartość 4 i 2 , z czego 2 zostaną zapisane do wynikowej tablicy. Następnie zostaną porównane 4 i 8 , 4 zostaną zapisane, a na koniec porównane zostaną 6 i 8 . Odpowiednio zostanie zapisane 6, a dopiero po nim - 8. W efekcie otrzymamy wynikową tablicę: {2,4,6,8} . Jak to będzie wyglądać w kodzie Java? Aby przetworzyć ten algorytm, wygodnie będzie nam zastosować rekurencję:
public class Solution {
   public static void main(String[] args) {
       int[] testArr = new int[]{6, 3, 8, 8, 6, 9, 4, 11, 1};
       testArr = mergeSort(testArr);
       for (int i : testArr) {
           System.out.println(i);
       }
   }

   public static int[] mergeSort(int[] array1) {
       int[] sortArr = Arrays.copyOf(array1, array1.length);// массив для сортировки
       int[] bufferArr = new int[array1.length];// буферный массив
       return recurtionMergeSort(sortArr, bufferArr, 0, array1.length);
   }


   public static int[] recurtionMergeSort(int[] sortArr, int[] bufferArr,
                                          int startIndex, int endIndex) {
       if (startIndex >= endIndex - 1) {// выход из массива, когда в рассматриваемом промежутке массива, только один элемент
           return sortArr;
       }

       // запускаем рекурсию, чтобы получить два отсортированных массива:
       int middle = startIndex + (endIndex - startIndex) / 2;
       int[] firstSortArr = recurtionMergeSort(sortArr, bufferArr, startIndex, middle);
       int[] secondSortArr = recurtionMergeSort(sortArr, bufferArr, middle, endIndex);

       // Слияние отсортированных массивов:
       int firstIndex = startIndex;
       int secondIndex = middle;
       int destIndex = startIndex;
       int[] result = firstSortArr == sortArr ? bufferArr : sortArr;
       while (firstIndex < middle && secondIndex < endIndex) {
           result[destIndex++] = firstSortArr[firstIndex] < secondSortArr[secondIndex]
                   ? firstSortArr[firstIndex++] : secondSortArr[secondIndex++];
       }
       while (firstIndex < middle) {
           result[destIndex++] = firstSortArr[firstIndex++];
       }
       while (secondIndex < endIndex) {
           result[destIndex++] = secondSortArr[secondIndex++];
       }
       return result;
   }
}
Podobnie jak w przypadku szybkiego sortowania, przenosimy metodę rekurencyjną do metody pośredniej, dzięki czemu użytkownik nie musi zawracać sobie głowy ustawianiem dodatkowych domyślnych argumentów, a może po prostu określić tablicę, która ma zostać posortowana. Ponieważ ten algorytm jest podobny do szybszego usuwania, jego szybkość wykonania jest taka sama - O(N*logN) .

2. Chciwe algorytmy

Algorytm zachłanny to podejście, które na każdym etapie podejmuje lokalnie optymalne decyzje i zakłada, że ​​ostateczne rozwiązanie również będzie optymalne. „Optymalne” rozwiązanie to takie, które oferuje najbardziej oczywistą i natychmiastową korzyść na danym etapie/etapie. Aby rozważyć ten algorytm, wybierzemy dość powszechny problem - dotyczący plecaka. Udawajmy przez chwilę, że jesteś złodziejem. Włamałeś się nocą do sklepu z plecakiem, a przed tobą leży szereg towarów, które możesz ukraść. Ale jednocześnie pojemność plecaka jest ograniczona - nie więcej niż 30 konwencjonalnych jednostek. Jednocześnie chcesz przewozić zestaw towarów o maksymalnej wartości, który zmieści się w Twoim plecaku. Jak decydujesz, co umieścić? Zatem algorytm zachłanny dla problemu plecakowego składa się z następujących kroków (zakładamy, że wszystkie obiekty mieszczą się w plecaku):
  1. Wybierz najdroższy przedmiot spośród tych, których jeszcze nie dotknąłeś.
  2. Jeśli zmieści się w Twoim plecaku, umieść go tam, jeśli nie, pomiń go.
  3. Czy przejrzałeś wszystkie elementy? Jeśli nie, wracamy do punktu 1, jeśli tak, uciekamy ze sklepu, ponieważ nasz cel tutaj został zrealizowany.
O co pytają na rozmowie kwalifikacyjnej: przegląd algorytmów, część 1 - 4Spójrzmy na to, ale w Javie. Tak będzie wyglądać klasa Item:
public class Item implements Comparable<Item> {
   private String name;
   private int weight;
   private int cost;

   public Item(String name, int weight, int cost) {
       this.name = name;
       this.weight = weight;
       this.cost = cost;
   }

   public String getName() {
       return name;
   }

   public int getWeight() {
       return weight;
   }

   public int getCost() {
       return cost;
   }

   @Override
   public int compareTo(Item o) {
       return this.cost > o.cost ? -1 : 1;
   }
}
Nie ma tu nic specjalnego: trzy pola – nazwa , waga , koszt – służące do określenia cech towaru. Jak widać, zaimplementowano tutaj interfejs Porównywalny , dzięki któremu możemy sortować nasze Przedmioty według ceny. Następnie patrzymy na klasę naszego plecaka - Torby :
public class Bag {
   private final int maxWeight;
   private List<Item> items;
   private int currentWeight;
   private int currentCost;

   public Bag(int maxWeight) {
       this.maxWeight = maxWeight;
       items = new ArrayList<>();
       currentCost = 0;
   }

   public int getMaxWeight() {
       return maxWeight;
   }

   public int getCurrentCost() {
       return currentCost;
   }

   public int getCurrentWeight() {
       return currentWeight;
   }

   public void addItem(Item item) {
       items.add(item);
       currentWeight += item.getWeight();
       currentCost += item.getCost();
   }
}
  • maxWeight to pojemność naszego plecaka, którą ustalamy podczas tworzenia obiektu;
  • przedmioty — przedmioty w plecaku;
  • currentWeight , currentCost – aktualna waga i koszt wszystkich rzeczy w plecaku, który zwiększamy dodając nowy przedmiot w metodzie addItem .
Właściwie przejdźmy do zajęć, w których dzieje się cała akcja:
public class Solution {

   public static void main(String[] args) {
       List<Item> items = new ArrayList<>();
       items.add(new Item("гитара",7, 800));
       items.add(new Item("утюг",6, 500));
       items.add(new Item("чайник",3, 300));
       items.add(new Item("лампа",4, 500));
       items.add(new Item("телевизор",15, 2000));
       items.add(new Item("ваза",2, 450));
       items.add(new Item("миксер",1, 400));
       items.add(new Item("блендер",3, 200));

       Collections.sort(items);

       Bag firstBag = new Bag(30);

       fillBackpack(firstBag, items);

       System.out.println("Вес рюкзака состовляет - " + firstBag.getCurrentWeight() +
               ", общая стоимость вещей в рюкзаке - " + firstBag.getCurrentCost());
}
}
Najpierw tworzymy listę elementów i sortujemy ją. Utwórz obiekt w postaci torby o pojemności 30 jednostek. Następnie wysyłamy elementy oraz obiekt torby do metody fillBackpack , w której tak naprawdę plecak jest zapełniany za pomocą zachłannego algorytmu:
public static void fillBackpack(Bag bag, List<Item> items) {
   for (Item item : items) {
       if(bag.getMaxWeight() > bag.getCurrentWeight() + item.getWeight()) {
            bag.addItem(item);
       }
   }
}
Wszystko jest niezwykle proste: zaczynamy przeglądać listę przedmiotów posortowanych według kosztów i wkładamy je do torby, jeśli pozwala na to pojemność. Jeśli to nie pozwoli, element zostanie pominięty, a przejście przez pozostałe elementy będzie kontynuowane aż do końca listy. Uruchamiając main, otrzymujemy na konsolę następujące dane wyjściowe:
Waga plecaka to 29, całkowity koszt rzeczy w plecaku to 3700
Właściwie jest to przykład algorytmu zachłannego: na każdym kroku wybierane jest rozwiązanie lokalnie optymalne, a na koniec otrzymujesz rozwiązanie optymalne globalnie. W naszym przypadku najlepszą opcją jest najdroższy przedmiot. Ale czy to najlepsze rozwiązanie? Czy nie sądzicie, że moglibyśmy trochę unowocześnić nasze rozwiązanie tak, abyśmy mogli wyposażyć plecak większym kosztem całkowitym? Przyjrzyjmy się, jak można to zrobić:
public static void effectiveFillBackpack(Bag bag, List<Item> items) {
   Map<Double, Item> sortByRatio = new TreeMap(Collections.reverseOrder());
   for (Item item : items) {
       sortByRatio.put((double)item.getCost() / item.getWeight(), item);
   }

   for (Map.Entry<Double, Item> entry : sortByRatio.entrySet()) {
       if(bag.getMaxWeight() > bag.getCurrentWeight() + entry.getValue().getWeight()) {
           bag.addItem(entry.getValue());
       }
   }
}
Tutaj najpierw obliczamy stosunek wagi do ceny dla każdego artykułu. Że tak powiem, ile kosztuje jedna jednostka danego przedmiotu? I według tych wartości sortujemy nasze przedmioty i dodajemy je do naszej torby. Biegnijmy:
Bag secondBag = new Bag(30);

effectiveFillBackpack(secondBag, items);

System.out.println("Вес рюкзака составляет - " + secondBag.getCurrentWeight() +
       ", общая стоимость вещей в рюкзаке - " + secondBag.getCurrentCost());
Otrzymujemy dane wyjściowe na konsolę:
Waga plecaka to 29, całkowity koszt rzeczy w plecaku to 4150
Trochę lepiej, prawda? Algorytm zachłanny dokonuje na każdym etapie wyboru lokalnie optymalnego, oczekując, że rozwiązanie końcowe również będzie optymalne. Nie zawsze jest to uzasadnione, ale w przypadku wielu problemów zachłanne algorytmy rzeczywiście zapewniają optymalne rozwiązanie. Złożoność czasowa tego algorytmu wynosi O(N) , co jest całkiem niezłe, prawda? Na tym zakończyła się pierwsza część tego artykułu. Jeśli interesuje Cię ciąg dalszy artykułu, w którym omówione zostaną wykresy i związane z nimi algorytmy, znajdziesz go tutaj .O co pytają na rozmowie kwalifikacyjnej: przegląd algorytmów, część 1 - 5
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION