Website Summary Files Commits Branches @commit @diff @stats
path: root / Week11
diff options
context:
space:
mode:
Commit6bb7b68394ebebbc69e76bee59e9351386115453 (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-12-14 21:56:30 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-12-14 21:56:30 +0200
Filesc31eb47780b5bfe4d038b6d6b8f32a385d717b96 /Week11
upp-2025-solutions-6bb7b68394ebebbc69e76bee59e9351386115453.tar
upp-2025-solutions-6bb7b68394ebebbc69e76bee59e9351386115453.tar.gz
upp-2025-solutions-6bb7b68394ebebbc69e76bee59e9351386115453.zip
Parent5ce214686e668bf185222b518b78d7f47a20b4fd (diff)
feat(Week11): Add solutions
15 files changed, 669 insertions, 0 deletions
-rw-r--r--Week11/Exercise01.cpp13
-rw-r--r--Week11/Exercise02.cpp82
-rw-r--r--Week11/Exercise03.cpp64
-rw-r--r--Week11/Exercise04.cpp23
-rw-r--r--Week11/Exercise05.cpp28
-rw-r--r--Week11/Exercise06.cpp37
-rw-r--r--Week11/Exercise07.cpp48
-rw-r--r--Week11/Exercise08.cpp77
-rw-r--r--Week11/Exercise09.cpp53
-rw-r--r--Week11/Exercise10.cpp31
-rw-r--r--Week11/Exercise11.cpp48
-rw-r--r--Week11/Exercise12.cpp60
-rw-r--r--Week11/Exercise13.cpp42
-rw-r--r--Week11/Exercise14.cpp60
-rw-r--r--Week11/README.md3
diff --git a/Week11/Exercise01.cpp b/Week11/Exercise01.cpp
new file mode 100644
index 0000000..784c5ac
--- /dev/null
+++ b/Week11/Exercise01.cpp
@@ -0,0 +1,13 @@
+#include <iostream>
+
+int main() {
+ const unsigned NAME_LENGTH = 20;
+
+ // 20 букви за името и 1 буква за терминиращата нула
+ char name[NAME_LENGTH + 1];
+ std::cin.getline(name, NAME_LENGTH + 1);
+
+ std::cout << "Hello, " << name << "!" << std::endl;
+
+ return 0;
+}
diff --git a/Week11/Exercise02.cpp b/Week11/Exercise02.cpp
new file mode 100644
index 0000000..9041fab
--- /dev/null
+++ b/Week11/Exercise02.cpp
@@ -0,0 +1,82 @@
+#include <iostream>
+
+/* Предлагам три решения на тази задача */
+
+unsigned countLetters(const char* str) {
+ unsigned count = 0;
+ while (*str != '\0') {
+ count += ('A' <= *str && *str <= 'Z') ||
+ ('a' <= *str && *str <= 'z');
+ ++str;
+ }
+ return count;
+}
+
+// Избираме си максимален размер за низа
+void solution1() {
+ const unsigned MAX_LENGTH = 1024;
+
+ char sentence[MAX_LENGTH];
+ std::cin.getline(sentence, MAX_LENGTH, '.');
+
+ std::cout << countLetters(sentence) << std::endl;
+}
+
+// Низа може да бъде произволно дълъг
+void solution2() {
+ // Заделяме памет за низа, следим колко букви сме вкарали в низа.
+ // Ако запълним заделената памет, реоразмеряваме масива (правим
+ // го по-голям).
+
+ unsigned allocated = 8, size = 0;
+ char* sentence = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '.') {
+ sentence[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = sentence[i];
+
+ delete[] sentence;
+ sentence = newSentenceArray;
+ }
+ }
+ sentence[size] = '\0';
+
+ std::cout << countLetters(sentence) << std::endl;
+
+ delete[] sentence;
+}
+
+// В тази конкретна задача, не е нужно да запазваме
+// целия низ и после да гледаме буквите, можем директно
+// да анализираме входа буква по буква
+void solution3() {
+ unsigned count = 0;
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '.') {
+ count += ('A' <= curr && curr <= 'Z') ||
+ ('a' <= curr && curr <= 'z');
+ std::cin.get(curr);
+ }
+
+ std::cout << count << std::endl;
+}
+
+int main() {
+ // solution1();
+ // solution2();
+ solution3();
+
+ return 0;
+}
diff --git a/Week11/Exercise03.cpp b/Week11/Exercise03.cpp
new file mode 100644
index 0000000..3620061
--- /dev/null
+++ b/Week11/Exercise03.cpp
@@ -0,0 +1,64 @@
+#include <iostream>
+
+unsigned fieldsCount(const char* str) {
+ // Едно поле не съдържа шпации, което реално означава, че
+ // всяко поле ще бъде заобиколено от шпации (с леко изключение
+ // на първото и последното поле).
+ //
+ // В такъв случай, можем да кажем, че началото на поле се "маркира"
+ // с първата не-шпация след редица от шпации. Тоест, ако текущия
+ // знак не е шпация, достатъчно е да погледнем предходния знак, за да
+ // разберем дали сме започнали поле или сме по средата на поле.
+ //
+ // И за нашата задача, остава само да преборим тези начала, което е
+ // същото като броя полета. Допълнително, ако инициализираме
+ // предходната буква да е шпация, тогава винаги ще преборим първото
+ // поле.
+ //
+ // Да, задачата може да се реши без запазването на целия низ.
+
+ unsigned count = 0;
+
+ char prev = ' ';
+ char curr = *(str++);
+
+ while (curr != '\0') {
+ count += prev == ' ' && curr != ' ';
+
+ prev = curr;
+ curr = *(str++);
+ }
+
+ return count;
+}
+
+int main() {
+ unsigned allocated = 8, size = 0;
+ char* sentence = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '.') {
+ sentence[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = sentence[i];
+
+ delete[] sentence;
+ sentence = newSentenceArray;
+ }
+ }
+ sentence[size] = '\0';
+
+ std::cout << fieldsCount(sentence) << std::endl;
+
+ delete[] sentence;
+
+ return 0;
+}
diff --git a/Week11/Exercise04.cpp b/Week11/Exercise04.cpp
new file mode 100644
index 0000000..081973b
--- /dev/null
+++ b/Week11/Exercise04.cpp
@@ -0,0 +1,23 @@
+#include <iostream>
+
+int main() {
+ char prev = '\0', curr = prev;
+ std::cin.get(curr);
+
+ // Всеки ред се бележи с \n накрая. Ако имаме празен ред,
+ // то целия ред ще съдържа само \n.
+ // Тоест, ако имаме ред с текст, и директно след него "празен"
+ // ред, то ще имаме две \n в последователност.
+
+ unsigned count = 0;
+ while (prev != '\n' || curr != '\n') {
+ count += curr == '\n';
+
+ prev = curr;
+ std::cin.get(curr);
+ }
+
+ std::cout << count << std::endl;
+
+ return 0;
+}
diff --git a/Week11/Exercise05.cpp b/Week11/Exercise05.cpp
new file mode 100644
index 0000000..5177003
--- /dev/null
+++ b/Week11/Exercise05.cpp
@@ -0,0 +1,28 @@
+#include <iostream>
+
+int main() {
+ const unsigned SIZE = 1024;
+
+ char str[SIZE];
+ std::cin.getline(str, SIZE, ':');
+ double a, b;
+ std::cin >> a >> b;
+
+ for (unsigned i = 0; str[i] != '\0' && str[i+2] != '\0'; i++) {
+ if (str[i] == 's' &&
+ str[i+1] == 'u' &&
+ str[i+2] == 'm')
+ {
+ std::cout << (a + b) << ' ';
+ }
+ else if (str[i] == 's' &&
+ str[i+1] == 'u' &&
+ str[i+2] == 'b')
+ {
+ std::cout << (a - b) << ' ';
+ }
+ }
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/Week11/Exercise06.cpp b/Week11/Exercise06.cpp
new file mode 100644
index 0000000..82860d1
--- /dev/null
+++ b/Week11/Exercise06.cpp
@@ -0,0 +1,37 @@
+#include <iostream>
+
+int main() {
+ const unsigned MAX_LENGTH = 128;
+ char num[MAX_LENGTH];
+ std::cin.getline(num, MAX_LENGTH);
+
+ const char* digit = num + 2;
+ unsigned long number = 0;
+
+ while (*digit != '\0') {
+ // Когато разглеждахме операции с цифри (добавяне/премахване на цифра от число),
+ // тогава говорехме как с деление на 10 премаваме цифра и с умножение на 10 я
+ // добавяме в десния край на числото.
+ //
+ // Това работи, защото цифрите ни са в десетична бройна система. Ако работехме
+ // например с двоична, тогава щяхме да делим и умножаваме с 2, за да махаме/добавяме
+ // "цифри" в края на числото (да се има впредвид, че резултата ще е в 10тична бройна
+ // система).
+ //
+ // Аналогично, понеже работим с 16тична, правим операции с числото 16.
+
+ if ('0' <= *digit && *digit <= '9') {
+ number = number * 16 + (*digit - '0');
+ }
+ // А e 10, B е 11, ..., F е 15
+ else if ('A' <= *digit && *digit <= 'F') {
+ number = number * 16 + (*digit - 'A' + 10);
+ }
+
+ ++digit;
+ }
+
+ std::cout << number << std::endl;
+
+ return 0;
+}
diff --git a/Week11/Exercise07.cpp b/Week11/Exercise07.cpp
new file mode 100644
index 0000000..e434919
--- /dev/null
+++ b/Week11/Exercise07.cpp
@@ -0,0 +1,48 @@
+#include <iostream>
+
+int main() {
+ const unsigned PATTERN_SIZE = 5;
+ char pattern[PATTERN_SIZE + 1];
+ std::cin.getline(pattern, PATTERN_SIZE+1);
+
+ unsigned allocated = 8, size = 0;
+ char* text = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '\n') {
+ text[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = text[i];
+
+ delete[] text;
+ text = newSentenceArray;
+ }
+ }
+ text[size] = '\0';
+
+ unsigned matches = 0;
+ for (unsigned i = 0; i < size - PATTERN_SIZE + 1; i++) {
+ bool allMatch = true;
+
+ // Проверяваме дали от текущата буква в текста, нататък,
+ // низа съвпада с шаблона.
+ for (unsigned j = 0; j < PATTERN_SIZE; j++)
+ allMatch = allMatch && (text[i + j] == pattern[j]);
+
+ matches += allMatch;
+ }
+
+ std::cout << matches << std::endl;
+
+ delete[] text;
+
+ return 0;
+}
diff --git a/Week11/Exercise08.cpp b/Week11/Exercise08.cpp
new file mode 100644
index 0000000..7807913
--- /dev/null
+++ b/Week11/Exercise08.cpp
@@ -0,0 +1,77 @@
+#include <iostream>
+
+bool strneq(const char* str1, const char* str2, unsigned n) {
+ // Грозно е, но е добро упражнение за реда на операции
+ while (*str1 != '\0' && *str2 != '\0' && n-- > 0) {
+ if (*str1++ != *str2++)
+ return false;
+ }
+ return true;
+}
+
+void printField(const char* str) {
+ while (*str != ' ' && *str != '\0') {
+ std::cout << *str++;
+ }
+}
+
+int main() {
+ // Кодът е написан, допускайки че "end" е единствената
+ // възможна дума, обозначаваща край.
+ // Как може да се пренапише, така че да можем да си
+ // изберем произволен низ, обозначаващ край?
+
+ unsigned allocated = 8, size = 0;
+ char* text = new char[allocated];
+
+ std::cin.get(text[size++]);
+ std::cin.get(text[size++]);
+ std::cin.get(text[size++]);
+
+ char curr;
+ while (!strneq(text + size - 3, "end", 3)) {
+ std::cin.get(curr);
+ text[size++] = curr;
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = text[i];
+
+ delete[] text;
+ text = newSentenceArray;
+ }
+ }
+ text[size] = '\0';
+
+ // Обикаляме отзад-напред. В момента в който стигнем началото на поле
+ // (а именно, не-шпация преди която имаме шпация), тогава изкарваме
+ // полето. Тоест започваме временно да се движим напред, докато не
+ // сме изразходили буквите, съставящи полето.
+ //
+ // Тази схема очевидно оставя полето от първата буква непринтирано.
+
+ bool prevNonSpace = false;
+ for (int i = size - 1; i >= 0; i--) {
+ if (text[i] != ' ') {
+ prevNonSpace = true;
+ continue;
+ }
+
+ if (prevNonSpace) {
+ printField(text + i + 1);
+ prevNonSpace = false;
+ }
+
+ std::cout << text[i];
+ }
+ printField(text);
+ std::cout << std::endl;
+
+ delete[] text;
+
+ return 0;
+}
diff --git a/Week11/Exercise09.cpp b/Week11/Exercise09.cpp
new file mode 100644
index 0000000..5091b2f
--- /dev/null
+++ b/Week11/Exercise09.cpp
@@ -0,0 +1,53 @@
+#include <iostream>
+
+char* getField() {
+ unsigned allocated = 8, size = 0;
+ char* output = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+
+ while (curr != ' ' && curr != '\n' && curr != '\0') {
+ output[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = output[i];
+
+ delete[] output;
+ output = newSentenceArray;
+ }
+ }
+ output[size] = '\0';
+
+ return output;
+}
+
+int main() {
+ char* search = getField(), *pattern = getField();
+
+ // char е 8 битово, което означава че има 2^^8 = 256
+ // на брой различни възможни стойности.
+ // Знаем, че всяка буква всъщност е едно число, затова
+ // можем директно да го използваме като индекс.
+
+ unsigned occurrences[256] = { 0 };
+ for (const char* ser = search; *ser != '\0'; ser++)
+ occurrences[*ser]++;
+
+ unsigned sumOccurrences = 0;
+ for (const char* pat = pattern; *pat != '\0'; pat++)
+ sumOccurrences += occurrences[*pat];
+
+ std::cout << sumOccurrences << std::endl;
+
+ delete[] search;
+ delete[] pattern;
+
+ return 0;
+}
diff --git a/Week11/Exercise10.cpp b/Week11/Exercise10.cpp
new file mode 100644
index 0000000..4f42b06
--- /dev/null
+++ b/Week11/Exercise10.cpp
@@ -0,0 +1,31 @@
+#include <iostream>
+
+int main() {
+ const unsigned LINE_SIZE = 1024;
+
+ char line[LINE_SIZE];
+ std::cin.getline(line, LINE_SIZE);
+
+ // char е 8 битово, което означава че има 2^^8 = 256
+ // на брой различни възможни стойности.
+ // Знаем, че всяка буква всъщност е едно число, затова
+ // можем директно да го използваме като индекс.
+
+ bool encountered[256] = { 0 };
+ for (unsigned i = 0; line[i] != '\0'; i++)
+ encountered[line[i]] = true;
+
+ // Всички малки букви са отместени с 32 спрямо главните.
+ // Тоест, главна буква + 32 = съответната малка буква
+
+ bool isPangram = true;
+ for (char ch = 'A'; isPangram && ch <= 'Z'; ch++)
+ isPangram = encountered[ch] || encountered[ch + 32];
+
+ if (isPangram)
+ std::cout << "Pangram" << std::endl;
+ else
+ std::cout << "Not a pangram" << std::endl;
+
+ return 0;
+}
diff --git a/Week11/Exercise11.cpp b/Week11/Exercise11.cpp
new file mode 100644
index 0000000..988bea6
--- /dev/null
+++ b/Week11/Exercise11.cpp
@@ -0,0 +1,48 @@
+#include <iostream>
+
+bool streq(const char* str1, const char* str2) {
+ while (*str1 != '\0' && *str2 != '\0') {
+ if (*str1++ != *str2++)
+ return false;
+ }
+ return true;
+}
+
+unsigned strlen(const char* str) {
+ unsigned len = 0;
+ while (*str++ != '\0')
+ len++;
+ return len;
+}
+
+int main() {
+ const unsigned MAX_LINE_LENGTH = 1024;
+ char first[MAX_LINE_LENGTH], second[MAX_LINE_LENGTH];
+
+ std::cin.getline(first, MAX_LINE_LENGTH);
+ std::cin.getline(second, MAX_LINE_LENGTH);
+
+ // Как премахваме букви? Най-лесния начин е просто да ги презапишем.
+ // Все едно отместваме частта от низа след буквата, така че да се
+ // застъпи с това, което премахваме.
+ //
+ // Например, ако в "abcde" искаме да премахнем c, тогава просто
+ // на позицията на c ще запишем d, на позицията на d ще запишем е
+ // и на позицията на e ще запишем терминираща нула.
+
+ unsigned secondLen = strlen(second);
+
+ for (unsigned readIndex = 0, writeIndex = 0; first[readIndex] != '\0'; readIndex++, writeIndex++) {
+ if (streq(first + readIndex, second))
+ readIndex += secondLen;
+
+ if (readIndex != writeIndex) {
+ first[writeIndex] = first[readIndex];
+ first[writeIndex + 1] = '\0';
+ }
+ }
+
+ std::cout << first << std::endl;
+
+ return 0;
+}
diff --git a/Week11/Exercise12.cpp b/Week11/Exercise12.cpp
new file mode 100644
index 0000000..3ebb947
--- /dev/null
+++ b/Week11/Exercise12.cpp
@@ -0,0 +1,60 @@
+#include <iostream>
+
+unsigned passwordGrade(const char* password) {
+ unsigned charCount = 0;
+ bool containsLetter = false, containsDigit = false, containsSpecial = false, noNeighbouring = true;
+
+ while (*password != '\0') {
+ if (('a' <= *password && *password <= 'z') ||
+ ('A' <= *password && *password <= 'Z'))
+ {
+ containsLetter = true;
+ }
+ else if ('0' <= *password && *password <= '9') {
+ containsDigit = true;
+ }
+ else {
+ containsSpecial = true;
+ }
+
+ if (password[0] == password[1]) {
+ noNeighbouring = false;
+ }
+
+ charCount++;
+ password++;
+ }
+
+ return (charCount >= 15) + containsLetter + containsDigit + containsSpecial + noNeighbouring;
+}
+
+int main() {
+ unsigned allocated = 8, size = 0;
+ char* password = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '\n') {
+ password[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = password[i];
+
+ delete[] password;
+ password = newSentenceArray;
+ }
+ }
+ password[size] = '\0';
+
+ std::cout << passwordGrade(password) << std::endl;
+
+ delete[] password;
+
+ return 0;
+}
diff --git a/Week11/Exercise13.cpp b/Week11/Exercise13.cpp
new file mode 100644
index 0000000..ee7f57f
--- /dev/null
+++ b/Week11/Exercise13.cpp
@@ -0,0 +1,42 @@
+#include <iostream>
+
+unsigned fnvHash(const char* str) {
+ unsigned hash = 2166136261;
+ while (*str != '\0') {
+ hash *= 16777619;
+ hash ^= *str;
+ str++;
+ }
+ return hash;
+}
+
+int main() {
+ unsigned allocated = 8, size = 0;
+ char* sentence = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '\n') {
+ sentence[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = sentence[i];
+
+ delete[] sentence;
+ sentence = newSentenceArray;
+ }
+ }
+ sentence[size] = '\0';
+
+ std::cout << fnvHash(sentence) << std::endl;
+
+ delete[] sentence;
+
+ return 0;
+}
diff --git a/Week11/Exercise14.cpp b/Week11/Exercise14.cpp
new file mode 100644
index 0000000..4b62d3a
--- /dev/null
+++ b/Week11/Exercise14.cpp
@@ -0,0 +1,60 @@
+#include <iostream>
+
+char* getLine() {
+ unsigned allocated = 8, size = 0;
+ char* sentence = new char[allocated];
+
+ char curr;
+ std::cin.get(curr);
+ while (curr != '\n') {
+ sentence[size++] = curr;
+ std::cin.get(curr);
+
+ // Реоразмеряване
+ if (size >= allocated) {
+ allocated *= 2;
+ char* newSentenceArray = new char[allocated];
+
+ for (unsigned i = 0; i < size; i++)
+ newSentenceArray[i] = sentence[i];
+
+ delete[] sentence;
+ sentence = newSentenceArray;
+ }
+ }
+ sentence[size] = '\0';
+
+ return sentence;
+}
+
+int main() {
+ char* first = getLine(), *second = getLine();
+
+ bool foundCharacters[256] = { 0 };
+ for (char* f = first; *f != '\0'; f++)
+ foundCharacters[*f] = true;
+
+ bool isAnagram = true;
+ for (char* s = second; *s != '\0' && isAnagram; s++) {
+ // Малките букви са отместени от главните с 32,
+ // тоест всяка главна буква + 32 прави съответната малка буква
+ // (и обратно).
+
+ if ('A' <= *s && *s <= 'Z') {
+ isAnagram = foundCharacters[*s] || foundCharacters[*s + 32];
+ }
+ else if ('a' <= *s && *s <= 'z') {
+ isAnagram = foundCharacters[*s] || foundCharacters[*s - 32];
+ }
+ }
+
+ if (isAnagram)
+ std::cout << "Anagram" << std::endl;
+ else
+ std::cout << "Not an anagram" << std::endl;
+
+ delete[] first;
+ delete[] second;
+
+ return 0;
+}
diff --git a/Week11/README.md b/Week11/README.md
new file mode 100644
index 0000000..c42057c
--- /dev/null
+++ b/Week11/README.md
@@ -0,0 +1,3 @@
+# Задачи
+
+<https://syndamia.com/teaching/upp-2025/week11/>