diff --git a/otus-02/src/otus_02/homework/common_child.clj b/otus-02/src/otus_02/homework/common_child.clj index 04c5e8a..a321fd2 100644 --- a/otus-02/src/otus_02/homework/common_child.clj +++ b/otus-02/src/otus_02/homework/common_child.clj @@ -1,8 +1,8 @@ (ns otus-02.homework.common-child) -;; Строка называется потомком другой строки, -;; если она может быть образована путем удаления 0 или более символов из другой строки. +;; Строка S называется потомком другой строки P, +;; если она (S) может быть образована путем удаления 0 или более символов из другой строки (P). ;; Буквы нельзя переставлять. ;; Имея две строки одинаковой длины, какую самую длинную строку можно построить так, ;; чтобы она была потомком обеих строк? @@ -16,4 +16,35 @@ ;; Еще пример HARRY и SALLY. Ответ будет - 2, так как общий элемент у них AY -(defn common-child-length [fist-string second-string]) +;; Хелпер, который строит следующую строку dynamic programming таблицы по текущей +(defn next-row-helper [x y-seq row] + (loop [y-seq y-seq + row row + next-row '(0)] + (if (empty? y-seq) + next-row + (let [y (first y-seq) + top-left (first row) + top (first (rest row)) + left (first next-row) + d (if (= x y) (inc top-left) (max top left))] + (recur + (rest y-seq) + (rest row) + (conj next-row d)))))) + +;; По сути это задача на нахождение LCS (longest common subsequence) +;; Решение - dynamic programming, но без хранения всей таблицы в памяти, а только 2х строк: предыдущей и текущей +;; Ячейка на последней строке и последней строчке и будет является LCS +(defn common-child-length [x y] + (first + (let [x-seq (seq x) + y-seq (seq y)] + (loop [ + x-seq x-seq + row (repeat (inc (count y-seq)) 0)] + (if (empty? x-seq) + row + (recur + (rest x-seq) + (next-row-helper (first x-seq) y-seq (reverse row)))))))) \ No newline at end of file diff --git a/otus-02/src/otus_02/homework/palindrome.clj b/otus-02/src/otus_02/homework/palindrome.clj index dd3d8a4..2f51bf1 100644 --- a/otus-02/src/otus_02/homework/palindrome.clj +++ b/otus-02/src/otus_02/homework/palindrome.clj @@ -1,4 +1,22 @@ -(ns otus-02.homework.palindrome) +(ns otus-02.homework.palindrome + (:require [clojure.string :as str])) + +(defn is-palindrome [test-string] + (let [original (str/lower-case + (str/replace test-string #",|!|\?|\.|\s" "")) + reversed (str/reverse original)] + (= original reversed))) + + + + + + + + + + + + -(defn is-palindrome [test-string]) diff --git a/otus-02/src/otus_02/homework/pangram.clj b/otus-02/src/otus_02/homework/pangram.clj index cc35c99..d6cad09 100644 --- a/otus-02/src/otus_02/homework/pangram.clj +++ b/otus-02/src/otus_02/homework/pangram.clj @@ -1,4 +1,10 @@ -(ns otus-02.homework.pangram) +(ns otus-02.homework.pangram + (:require [clojure.string :as str])) +(defn is-char [ch] (Character/isLetter ch)) -(defn is-pangram [test-string]) +(defn is-pangram [test-string] + (let + [tested-char-set (set (filter is-char (str/lower-case test-string))) + all-chars (set (map char (range (int \a) (inc (int \z)))))] + (= tested-char-set all-chars))) diff --git a/otus-02/src/otus_02/homework/square_code.clj b/otus-02/src/otus_02/homework/square_code.clj index 823a185..2c892a0 100644 --- a/otus-02/src/otus_02/homework/square_code.clj +++ b/otus-02/src/otus_02/homework/square_code.clj @@ -1,4 +1,5 @@ -(ns otus-02.homework.square-code) +(ns otus-02.homework.square-code + (:require [clojure.string :as str])) ;; Реализовать классический метод составления секретных сообщений, называемый `square code`. ;; Выведите закодированную версию полученного текста. @@ -13,6 +14,9 @@ ;; нормализуется в строку: "ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" +(defn is-letter [c] (Character/isLetter c)) +(defn normalize [s] (filter is-letter (str/lower-case s))) + ;; Разбиваем текст в виде прямоугольника. ;; Размер прямоугольника (rows, cols) должен определяться длиной сообщения, ;; так что c >= r и c - r <= 1, где c — количество столбцов, а r — количество строк. @@ -26,15 +30,51 @@ "vegivenu" "sroots " +;; Чтение стобцов слева-направо в строку +(defn read-rectangle [rectangle] + (apply str + (loop [result '() + rectangle rectangle] + (if (empty? (first rectangle)) + result + (recur + (concat result (map first rectangle)) + (map rest rectangle)))))) + ;; Закодированное сообщение получается путем чтения столбцов слева направо. ;; Сообщение выше закодировано как: "imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" +(defn encode-helper [input] + (let [normalized (normalize input) + cnt (count normalized) + r (int (Math/sqrt cnt)) + c (if (< (* r r) cnt) (inc r) r) + rectangle (partition-all c normalized)] + (read-rectangle rectangle))) ;; Полученный закодированный текст разбиваем кусками, которые заполняют идеальные прямоугольники (r X c), ;; с кусочками c длины r, разделенными пробелами. ;; Для фраз, которые на n символов меньше идеального прямоугольника, ;; дополните каждый из последних n фрагментов одним пробелом в конце. "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " +(defn encode-string [input] + (let [ + input (encode-helper input) + cnt (count input) + cols-cnt (int (Math/sqrt cnt)) + rows-cnt (if (< (* cols-cnt cols-cnt) cnt) (inc cols-cnt) cols-cnt) + incomplete-cnt (- (* rows-cnt cols-cnt) cnt) + complete-cnt (- rows-cnt incomplete-cnt) + sub-str-cnt (* complete-cnt cols-cnt) + complete-sub-str (subs input 0 sub-str-cnt) + incomplete-sub-str (subs input sub-str-cnt) + complete-slices (partition-all cols-cnt complete-sub-str) + incomplete-slices (partition-all (dec cols-cnt) incomplete-sub-str)] + (str/join + " " + (concat + (map #(apply str %) complete-slices) + (map #(apply str (concat % '(\space))) incomplete-slices))))) ;; Обратите внимание, что если бы мы сложили их, ;; мы могли бы визуально декодировать зашифрованный текст обратно в исходное сообщение: @@ -48,9 +88,6 @@ "aohghn " "sseoau " +(defn decode-string [input] + (read-rectangle (str/split input #"\s+"))) - -(defn encode-string [input]) - - -(defn decode-string [input])