diff --git a/C3100_tregubov_vadim_lab4.cpp b/C3100_tregubov_vadim_lab4.cpp new file mode 100644 index 00000000..090dc5c3 --- /dev/null +++ b/C3100_tregubov_vadim_lab4.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +using namespace std; + +// функция для подсчета суммы отклонений в кластере +double calculateClusterCost(const vector& arr, int start, int end) { + double mean = 0; + for (int i = start; i <= end; ++i) { + mean += arr[i]; + } + mean /= (end - start + 1); // среднее значение кластера + + double cost = 0; + for (int i = start; i <= end; ++i) { + cost += abs(arr[i] - mean); // сумма модулей отклонений + } + return cost; +} + +// рекурсивная функция для поиска оптимального разбиения +void findOptimalClustering(const vector& arr, int k, int start, vector& currentCluster, vector>& bestClusters, double& minCost) { + if (k == 1) { + // базовый случай: один кластер от start до конца массива + double cost = calculateClusterCost(arr, start, arr.size() - 1); + if (cost < minCost) { + minCost = cost; + bestClusters.clear(); + bestClusters.push_back(vector(arr.begin() + start, arr.end())); + } + return; + } + + // перебираем все возможные позиции разделения кластера + for (int i = start; i < arr.size() - (k - 1); ++i) { + // добавляем текущий кластер + for (int j = start; j <= i; ++j) { + currentCluster.push_back(arr[j]); + } + + // рекурсивно ищем разбиение для оставшихся кластеров + vector nextCluster; + findOptimalClustering(arr, k - 1, i + 1, nextCluster, bestClusters, minCost); + + // удаляем текущий кластер + currentCluster.clear(); + } +} + +// основная функция кластеризации +vector> clusterArray(const vector& arr, int k) { + vector> bestClusters; + double minCost = numeric_limits::max(); + vector currentCluster; + + findOptimalClustering(arr, k, 0, currentCluster, bestClusters, minCost); + + return bestClusters; +} + +int main() { + vector arr = {1, -2, 3, 4, -5, 6}; + int k = 3; + + vector> clusters = clusterArray(arr, k); + + cout << "Кластеры:" << endl; + for (size_t i = 0; i < clusters.size(); ++i) { + cout << "Кластер " << i + 1 << ": "; + for (int num : clusters[i]) { + cout << num << " "; + } + cout << endl; + } + + /* + Время: + calculateClusterCost: O(n) для вычисления среднего и суммы отклонений. + findOptimalClustering: O(n * k) из-за перебора всех возможных разбиений. + Итого: O(n^2 * k) в худшем случае из-за рекурсивного перебора. + + Память: + Используется O(n) для хранения текущего кластера и O(n) для хранения лучших кластеров. + Итого: O(n). + + Итоговая асимптотика: + - calculateClusterCost: O(n) на каждое вычисление + - заполнение dp: O(k * n^2), так как перебираем все разбиения + - восстановление разбиения: O(k), так как идем по split + Итого: O(k * n^2), что гораздо быстрее рекурсивного O(n^k) + */ + + return 0; +} + diff --git a/c3100_tregubov_vadim_lab3 b/c3100_tregubov_vadim_lab3 new file mode 100644 index 00000000..ff9e089f --- /dev/null +++ b/c3100_tregubov_vadim_lab3 @@ -0,0 +1,34 @@ +#include +#include +#include +#include +using namespace std; + +void fisherYatesShuffle(vector& arr) { + random_device rd; // O(1) + mt19937 gen(rd()); // O(1) + + for (int i = arr.size() - 1; i > 0; i--) { // O(N) + uniform_int_distribution<> dis(0, i); // O(1) + int j = dis(gen); // O(1) + swap(arr[i], arr[j]); // O(1) + } +} + +int main() { + int n = 10; // O(1) + vector arr(n); // O(N) + + for (int i = 0; i < n; i++) { // O(N) + arr[i] = i + 1; // O(1) + } + + fisherYatesShuffle(arr); // O(N) + + for (int num : arr) { // O(N) + cout << num << " "; // O(1) + } + cout << endl; // O(1) + + return 0; +} diff --git a/lab0.cpp b/lab0.cpp new file mode 100644 index 00000000..ec14d6a4 --- /dev/null +++ b/lab0.cpp @@ -0,0 +1,30 @@ +#include + +int secondLargest(int arr[], int size) { + int first = -1; + int second = -1; + + for (int i = 0; i < size; i++) { + if (arr[i] > first) { + second = first; + first = arr[i]; + } + else if (arr[i] > second and arr[i] != first) { + second = arr[i]; + } + } + + return second; +} + +int main() { + int array[] = {1, 5, 2, 54, 23, 56, 7}; + int size = sizeof(array) / sizeof(array[0]); + + int answer = secondLargest(array, size); + + std::cout << answer; + + return 0; + +} diff --git a/lab4.cpp b/lab4.cpp new file mode 100644 index 00000000..79216d50 --- /dev/null +++ b/lab4.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +using namespace std; + +// Функция для подсчёта суммы отклонений в кластере +vector> costMatrix; + +void computeCostMatrix(const vector& arr) { + int n = arr.size(); + costMatrix.assign(n, vector(n, 0)); + + for (int i = 0; i < n; ++i) { + double sum = 0, mean = 0; + for (int j = i; j < n; ++j) { + sum += arr[j]; + mean = sum / (j - i + 1); + double cost = 0; + for (int k = i; k <= j; ++k) { + cost += abs(arr[k] - mean); + } + costMatrix[i][j] = cost; + } + } +} + +// Функция для разбиения массива на k кластеров +vector> clusterArray(const vector& arr, int k) { + int n = arr.size(); + computeCostMatrix(arr); + + vector> dp(k, vector(n, numeric_limits::max())); + vector> split(k, vector(n, -1)); + + for (int j = 0; j < n; ++j) { + dp[0][j] = costMatrix[0][j]; + } + + for (int clusters = 1; clusters < k; ++clusters) { + for (int j = clusters; j < n; ++j) { + for (int i = clusters - 1; i < j; ++i) { + double cost = dp[clusters - 1][i] + costMatrix[i + 1][j]; + if (cost < dp[clusters][j]) { + dp[clusters][j] = cost; + split[clusters][j] = i; + } + } + } + } + + vector> clusters(k); + int end = n - 1; + for (int i = k - 1; i >= 0; --i) { + int start = (i > 0) ? split[i][end] + 1 : 0; + clusters[i].assign(arr.begin() + start, arr.begin() + end + 1); + end = start - 1; + } + + return clusters; +} + +int main() { + vector arr = {1, -2, 3, 4, -5, 6}; + int k = 3; + + vector> clusters = clusterArray(arr, k); + + cout << "Кластеры:" << endl; + for (size_t i = 0; i < clusters.size(); ++i) { + cout << "Кластер " << i + 1 << ": "; + for (int num : clusters[i]) { + cout << num << " "; + } + cout << endl; + } + + /* + Время: + calculateClusterCost: O(n) для вычисления среднего и суммы отклонений. + findOptimalClustering: O(n * k) из-за перебора всех возможных разбиений. + Итого: O(n^2 * k) в худшем случае из-за рекурсивного перебора. + + Память: + Используется O(n) для хранения текущего кластера и O(n) для хранения лучших кластеров. + Итого: O(n). + + Итоговая асимптотика: + - calculateClusterCost: O(n) на каждое вычисление + - заполнение dp: O(k * n^2), так как перебираем все разбиения + - восстановление разбиения: O(k), так как идем по split + Итого: O(k * n^2), что гораздо быстрее рекурсивного O(n^k) + */ + + return 0; +} diff --git a/lab5.cpp b/lab5.cpp new file mode 100644 index 00000000..6069d1a8 --- /dev/null +++ b/lab5.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; + +// Сортировка методом Bucket Sort +void bucketSort(vector& arr) { + int n = arr.size(); + vector> buckets(n); + + for (double num : arr) { + int bucketIndex = static_cast(num * n); + buckets[bucketIndex].push_back(num); + } + + for (auto& bucket : buckets) { + sort(bucket.begin(), bucket.end()); + } + + int index = 0; + for (const auto& bucket : buckets) { + for (double num : bucket) { + arr[index++] = num; + } + } +} + +// Память и сложность Bucket Sort: +/* +Память: +1. Вектора для корзин: O(n). +2. Исходный массив: O(n). +Итого: O(n). + +Время: +1. Распределение по корзинам: O(n). +2. Сортировка каждой корзины: O(n log(n/k)), где k - средний размер корзины. +Итого: O(n + n log(n/k)) ≈ O(n log n) в худшем случае. +*/ + +// Сортировка методом Heap Sort +void heapify(vector& arr, int n, int i) { + int largest = i; + int left = 2 * i + 1; + int right = 2 * i + 2; + + if (left < n && arr[left] > arr[largest]) + largest = left; + + if (right < n && arr[right] > arr[largest]) + largest = right; + + if (largest != i) { + swap(arr[i], arr[largest]); + heapify(arr, n, largest); + } +} + +void heapSort(vector& arr) { + int n = arr.size(); + + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + for (int i = n - 1; i >= 0; i--) { + swap(arr[0], arr[i]); + heapify(arr, i, 0); + } +} + +// Память и сложность Heap Sort: +/* +Память: +1. Исходный массив: O(n). +2. Дополнительный стек для рекурсии в heapify: O(log n). +Итого: O(n). + +Время: +1. Построение кучи: O(n). +2. Извлечение элементов: O(n log n). +Итого: O(n log n). +*/ + +// Сортировка методом Shaker Sort +void shakerSort(vector& arr) { + bool swapped = true; + int start = 0; + int end = arr.size() - 1; + + while (swapped) { + swapped = false; + + for (int i = start; i < end; ++i) { + if (arr[i] > arr[i + 1]) { + swap(arr[i], arr[i + 1]); + swapped = true; + } + } + + if (!swapped) + break; + + swapped = false; + --end; + + for (int i = end - 1; i >= start; --i) { + if (arr[i] > arr[i + 1]) { + swap(arr[i], arr[i + 1]); + swapped = true; + } + } + ++start; + } +} + +// Память и сложность Shaker Sort: +/* +Память: +1. Исходный массив: O(n). +2. Дополнительные переменные: O(1). +Итого: O(n). + +Время: +1. Худший случай: O(n^2) (если массив сильно неупорядочен). +2. Лучший случай: O(n) (если массив уже отсортирован). +*/ + +int main() { + // Пример для Bucket Sort + vector bucketArr = {0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.12, 0.23, 0.68}; + auto startBucket = chrono::high_resolution_clock::now(); + bucketSort(bucketArr); + auto endBucket = chrono::high_resolution_clock::now(); + for (double num : bucketArr) { + cout << num << " "; + } + cout << "\nВремя выполнения Bucket Sort: " + << chrono::duration_cast(endBucket - startBucket).count() << " микросекунд\n"; + + // Пример для Heap Sort + vector heapArr = {4, 10, 3, 5, 1}; + auto startHeap = chrono::high_resolution_clock::now(); + heapSort(heapArr); + auto endHeap = chrono::high_resolution_clock::now(); + for (int num : heapArr) { + cout << num << " "; + } + cout << "\nВремя выполнения Heap Sort: " + << chrono::duration_cast(endHeap - startHeap).count() << " микросекунд\n"; + + // Пример для Shaker Sort + vector shakerArr = {5, 3, 8, 6, 2, 7, 4, 1}; + auto startShaker = chrono::high_resolution_clock::now(); + shakerSort(shakerArr); + auto endShaker = chrono::high_resolution_clock::now(); + for (int num : shakerArr) { + cout << num << " "; + } + cout << "\nВремя выполнения Shaker Sort: " + << chrono::duration_cast(endShaker - startShaker).count() << " микросекунд\n"; + + return 0; +} diff --git a/lab6.cpp b/lab6.cpp new file mode 100644 index 00000000..bc58c4d8 --- /dev/null +++ b/lab6.cpp @@ -0,0 +1,30 @@ +class Solution { +public: + int uniquePaths(int m, int n) { + // подсчет памяти: + // - используем одномерный вектор dp размером n. + // - память: O(n), так как храним только одну строку таблицы DP. + + // асимптотика: + // - временная сложность: O(m * n), так как заполняем таблицу DP. + // - пространственная сложность: O(n), так как используем одномерный массив. + + // инициализация вектора dp: + // - dp[j] хранит количество путей до клетки (текущая строка, j). + // - изначально все элементы равны 1, так как в первой строке только один путь (вправо). + vector dp(n, 1); + + // заполнение таблицы DP: + // - для каждой строки (начиная со второй) обновляем значения dp[j]. + // - dp[j] = dp[j] (количество путей сверху) + dp[j - 1] (количество путей слева). + for (int i = 1; i < m; ++i) { + for (int j = 1; j < n; ++j) { + dp[j] += dp[j - 1]; + } + } + + // возвращаем количество путей до конечной клетки (m-1, n-1): + // - dp[n - 1] содержит результат для последней клетки. + return dp[n - 1]; + } +}; diff --git a/lab7.cpp b/lab7.cpp new file mode 100644 index 00000000..bd83ab06 --- /dev/null +++ b/lab7.cpp @@ -0,0 +1,34 @@ +class Solution { +public: + int minPatches(vector& nums, int n) { + // подсчет памяти: + // - используем несколько переменных: ans, i, miss. + // - память: O(1), так как не используем дополнительных структур данных. + + // асимптотика: + // - временная сложность: O(m + log n), где m — длина nums. + // - проходим по nums один раз (O(m)). + // - каждое удвоение miss занимает O(log n) шагов. + // - пространственная сложность: O(1). + + int ans = 0; // количество добавленных патчей + int i = 0; // индекс для обхода nums + long miss = 1; // минимальное число, которое мы не можем покрыть + + // пока miss <= n, продолжаем искать числа, которые нужно добавить + while (miss <= n) { + if (i < nums.size() && nums[i] <= miss) { + // если текущее число nums[i] <= miss, добавляем его к диапазону + // теперь мы можем покрыть все числа до miss + nums[i] - 1 + miss += nums[i++]; + } else { + // если nums[i] > miss или nums закончились, добавляем miss + // это увеличивает диапазон покрытия до 2 * miss + miss += miss; + ++ans; // увеличиваем счетчик добавленных патчей + } + } + + return ans; + } +}; diff --git "a/\320\236\321\202\321\207\320\265\321\202 \320\273\320\260\320\2615.docx" "b/\320\236\321\202\321\207\320\265\321\202 \320\273\320\260\320\2615.docx" new file mode 100644 index 00000000..68df2066 Binary files /dev/null and "b/\320\236\321\202\321\207\320\265\321\202 \320\273\320\260\320\2615.docx" differ