Skip to content

Commit

Permalink
Add missing questions
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhijit Sarkar committed Jan 2, 2024
1 parent 6faf008 commit 84b5275
Show file tree
Hide file tree
Showing 11 changed files with 535 additions and 48 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@

* Questions 11 to 20: [Lists, continued](src/Lists2.hs)

* Questions 21 to 28: [Lists again](src/Lists3.hs)
* Questions 21 to 30: [Lists again](src/Lists3.hs)

* Questions 31 to 41: [Arithmetic](src/Arithmetic.hs)
* Questions 31 to 45: [Arithmetic](src/Arithmetic.hs)

* Questions 46 to 50: [Logic and codes](src/Logic.hs)
* Questions 46 to 53: [Logic and codes](src/Logic.hs)

* Questions 54A to 60: [Binary trees](src/BinaryTrees.hs)

* Questions 61 to 69: [Binary trees, continued](src/BinaryTrees2.hs)

* Questions 70B to 73: [Multiway trees](src/MultiwayTrees.hs)

* Questions 74 to 79: [Monads](src/Monads.hs)

* Questions 80 to 89: [Graphs](src/Graphs.hs)

* Questions 90 to 94: [Miscellaneous problems](src/Misc.hs)

* Questions 95 to 99: [Miscellaneous problems, continued](src/Misc2.hs)

(Though the problems number from 1 to 99, there are some gaps and some additions marked with letters. There are actually only 88 problems.)

## Running tests

```
Expand Down
2 changes: 2 additions & 0 deletions ninety-nine-haskell.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ library
Logic
Misc
Misc2
Monads
MultiwayTrees
Parser
other-modules:
Expand Down Expand Up @@ -74,6 +75,7 @@ test-suite ninety-nine-test
LogicSpec
Misc2Spec
MiscSpec
MonadsSpec
MultiwayTreesSpec
SpecHook
Paths_ninety_nine_haskell
Expand Down
73 changes: 73 additions & 0 deletions src/Arithmetic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,76 @@ print a list of all even numbers and their Goldbach composition.
-}
goldbachList :: Int -> Int -> [(Int, Int)]
goldbachList lo hi = [goldbach x | x <- [lo .. hi], even x]

{-
Problem 42: (**) Modular multiplicative inverse.
In modular arithmetic, integers a and b being congruent modulo an integer n,
means that a - b = k * n, for some integer k.
Many of the usual rules for addition, subtraction, and multiplication in
ordinary arithmetic also hold for modular arithmetic.
A multiplicative inverse of an integer a modulo n is an integer x such that
ax is congruent to 1 with respect to n. It exists if and only if a and n
are coprime.
Write a function to compute the multiplicative inverse x of a given integer a
and modulus n lying in the range 0 <= x < n.
Use the extended Euclidean algorithm.
https://brilliant.org/wiki/extended-euclidean-algorithm/
-}
multiplicativeInverse :: (Integral a) => a -> a -> Maybe a
multiplicativeInverse a n
| a >= n = multiplicativeInverse (a `mod` n) n
| r == 1 = Just $ x `mod` n
| otherwise = Nothing
where
(r, x, _) = reduce (n, a) (0, 1) (1, 0)

reduce :: (Integral a) => (a, a) -> (a, a) -> (a, a) -> (a, a, a)
reduce (0, r') (_, x') (_, y') = (r', x', y')
reduce (r, r') (x, x') (y, y') = reduce (r' - q * r, r) (x' - q * x, x) (y' - q * y, y)
where
q = r' `div` r

{-
Problem 43: (*) Gaussian integer divisibility.
A Gaussian integer is a complex number where both the real and imaginary parts are integers.
If x and y are Gaussian integers where y /= 0, then x is said to be divisible by y if there
is a Guassian integer x such that x = yz.
Determine whether a Gaussian integer is divisible by another.
ANSWER: TODO.
-}

{-
Problem 44: (**) Gaussian primes.
A Gaussian integer x is said to be a Gaussian prime when it has no divisors except for the
units and associates of x. The units are 1, i - 1, and -i. The associates are defined by the
numbers obtained when x is multiplied by each unit.
Determine whether a Gaussian integer is a Gaussian prime.
ANSWER: TODO.
-}

{-
Problem 45: (*) Gaussian primes using the two-square theorem.
Using Fermat's two-square theorem, it can be shown that a Gaussian integer a + bi
is prime if and only if it falls into one of the following categories:
\|a| is prime and |𝑎| ≡ 3 mod 4, if 𝑏=0
\|b| is prime and |𝑏| ≡ 3 mod 4, if 𝑎=0
a^2 + b^2 is prime, if a /= 0 and b /= 0
Use this property to determine whether a Gaussian integer is a Gaussian prime.
ANSWER: TODO.
-}
22 changes: 11 additions & 11 deletions src/BinaryTrees2.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import qualified Data.List.Split as LS
import Parser (Parser (..))
import qualified Parser as P

-- Problem 61: Count the leaves of a binary tree.
-- Problem 61: (*) Count the leaves of a binary tree.
countLeaves :: Tree a -> Int
countLeaves Empty = 0
countLeaves (Branch _ l r) = case (l, r) of
(Empty, Empty) -> 1
_ -> countLeaves l + countLeaves r

-- Problem 61A: Collect the leaves of a binary tree in a list.
-- Problem 61A: (*) Collect the leaves of a binary tree in a list.
leaves :: Tree a -> [a]
leaves = go []
where
Expand All @@ -25,7 +25,7 @@ leaves = go []
(Empty, Empty) -> x : acc
_ -> go (go acc r) l

-- Problem 62: Collect the internal nodes of a binary tree in a list.
-- Problem 62: (*) Collect the internal nodes of a binary tree in a list.
internals :: Tree a -> [a]
internals = go []
where
Expand All @@ -34,7 +34,7 @@ internals = go []
(Empty, Empty) -> acc
_ -> x : go (go acc r) l

-- Problem 62B: Collect the nodes at a given level in a list.
-- Problem 62B: (*) Collect the nodes at a given level in a list.
atLevel :: Tree a -> Int -> [a]
atLevel = go []
where
Expand All @@ -43,7 +43,7 @@ atLevel = go []
| level == 1 = x : acc
| otherwise = go (go acc r (level - 1)) l (level - 1)

-- Problem 63: Construct a complete binary tree.
-- Problem 63: (**) Construct a complete binary tree.
{-
ANSWER:
Considering the height H of the tree as the number of edges on
Expand Down Expand Up @@ -85,7 +85,7 @@ type Pos = (Int, Int)
type AnnotatedTree a = Tree (a, Pos)

{-
Problem 64: Layout algorithm for displaying trees.
Problem 64: (**) Layout algorithm for displaying trees.
In this layout strategy, the position of a node v is obtained by the following two rules:
- x(v) is equal to the position of the node v in the inorder sequence
Expand All @@ -112,7 +112,7 @@ height Empty = -1
height (Branch _ l r) = 1 + max (height l) (height r)

{-
Problem 65: Layout algorithm for displaying trees (part 2).
Problem 65: (**) Layout algorithm for displaying trees (part 2).
ANSWER: In this problem, no two nodes share the same Y-coordinate.
Thus, the X-coordinate of a node is determined by the maximum
Expand Down Expand Up @@ -147,7 +147,7 @@ layout2 = fst . (go 1 1 =<< (2 *) . height)
node = Branch (x, (pos', depth)) left right

{-
Problem 66: Layout algorithm for displaying trees (part 3).
Problem 66: (***) Layout algorithm for displaying trees (part 3).
The method yields a very compact layout while maintaining a
certain symmetry in every node. Find out the rules and write
Expand All @@ -164,7 +164,7 @@ TODO.
-}

{-
Problem 67A: A string representation of binary trees.
Problem 67A: (**) A string representation of binary trees.
Write a predicate which generates this string representation.
Then write a predicate which does this inverse; i.e. given the
string representation, construct the tree in the usual form.
Expand Down Expand Up @@ -210,7 +210,7 @@ treeToString = D.toList . go D.empty
D.++ D.singleton ')'

{-
Problem 68: Preorder and inorder sequences of binary trees.
Problem 68: (**) Preorder and inorder sequences of binary trees.
a) Write predicates preorder and inorder that construct the
preorder and inorder sequence of a given binary tree,
Expand Down Expand Up @@ -258,7 +258,7 @@ preInTree pre = fst . build pre
(right, zs) = build ys io''

{-
Problem 69: Dotstring representation of binary trees.
Problem 69: (**) Dotstring representation of binary trees.
First, try to establish a syntax (BNF or syntax diagrams)
and then write a predicate tree_dotstring which does the
Expand Down
2 changes: 1 addition & 1 deletion src/Lists2.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Implement the so-called run-length encoding data
compression method directly.
-}

-- Problem 14: Duplicate the elements of a list.
-- Problem 14: (*) Duplicate the elements of a list.
dupli :: [a] -> [a]
dupli xs = repli xs 2 -- (take 2 . repeat =<<)

Expand Down
70 changes: 60 additions & 10 deletions src/Lists3.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import Data.List ((\\))
import qualified Data.List as L
import qualified System.Random as R

-- Problem 21: Insert an element at a given position into a list.
-- Problem 21: (*) Insert an element at a given position into a list.
insertAt :: a -> [a] -> Int -> [a]
insertAt x xs n
| n > 0 = left ++ [x] ++ right
| otherwise = error "invalid position"
where
(left, right) = L.splitAt (n - 1) xs

-- Problem 22: Create a list containing all integers within a given range.
-- Problem 22: (*) Create a list containing all integers within a given range.
range :: Int -> Int -> [Int]
range start end
| start <= end = [start .. end]
Expand All @@ -33,7 +33,7 @@ randomElems n m xs
let (left, x : right) = L.splitAt (k - 1) xs
(x :) <$> randomElems (n - 1) (m - 1) (left ++ right)

-- Problem 23: Extract a given number of randomly selected elements from a list.
-- Problem 23: (**) Extract a given number of randomly selected elements from a list.
-- Note: This implementation chooses with replacement.
rndSelect :: [a] -> Int -> IO [a]
rndSelect xs n
Expand All @@ -48,18 +48,18 @@ randomElem xs = i <&> (xs !!)
n = length xs
i = R.randomRIO (0, n - 1)

-- Problem 24: Draw N different random numbers from the set 1..M.
-- Problem 24: (*) Draw N different random numbers from the set 1..M.
-- Note: The selected elements are unique.
diffSelect :: Int -> Int -> IO [Int]
diffSelect n m = randomElems n m [1 .. m]

-- Problem 25: Generate a random permutation of the elements of a list.
-- Problem 25: (*) Generate a random permutation of the elements of a list.
rndPerm' :: [a] -> IO [a]
rndPerm' xs = randomElems n n xs
where
n = length xs

-- Problem 25: Generate a random permutation of the elements of a list.
-- Problem 25: (*) Generate a random permutation of the elements of a list.

{-
ANSWER: Alternative imperative solution.
Expand Down Expand Up @@ -98,7 +98,7 @@ combinations n xs = do
return (y : zs)

{-
Problem 27a: In how many ways can a group of 9 people
Problem 27a: (**) In how many ways can a group of 9 people
work in 3 disjoint subgroups of 2, 3 and 4 persons?
Write a function that generates all the possibilities
and returns them in a list.
Expand All @@ -107,7 +107,7 @@ group3 :: (Eq a) => [a] -> [[[a]]]
group3 = group [2 .. 4]

{-
Problem 27b: In how many ways can a group of 9 people
Problem 27b: (**) In how many ways can a group of 9 people
work in disjoint subgroups of the given sizes?
Write a function that generates all the possibilities
and returns them in a list.
Expand All @@ -120,16 +120,66 @@ group (i : is) xs = do
xxs <- group is (xs \\ ys)
return (ys : xxs)

-- Problem 28a: Sort the elements of this list according to their length;
-- Problem 28a: (**) Sort the elements of this list according to their length;
-- i.e short lists first, longer lists later.
lsort :: [[a]] -> [[a]]
lsort = L.sortOn length

-- Problem 28b: Sort the elements of this list according to their length frequency;
-- Problem 28b: (**) Sort the elements of this list according to their length frequency;
-- i.e., lists with rare lengths are placed first, others with a more frequent length come later.
lfsort :: [[a]] -> [[a]]
lfsort xxs = L.sortOn lenFreq xxs
where
ls = map length xxs
count x = (length . filter (== x)) ls
lenFreq xs = count (length xs)

{-
Problem 29: (*) Write a function to compute the nth Fibonacci number.
-}
fibonacci :: Int -> Int
fibonacci = go 0 1
where
go x _ 1 = x
go x y n = go y (x + y) (n - 1)

-- https://rosettacode.org/wiki/Matrix_multiplication#Haskell
-- Not the most efficient though.
mmult :: (Num a) => [[a]] -> [[a]] -> [[a]]
mmult a b = [[sum $ zipWith (*) ar bc | bc <- L.transpose b] | ar <- a]

{-
Problem 30: (**) Write a function to compute the nth Fibonacci number.
Consider the following matrix equation, where F(n) is the nth Fibonacci number:
\|x2| = |1 1| |F(n+1)|
\|x1| = |1 0| x |F(n) |
When written out as linear equations, this is equivalent to:
x2 = F(n+1) + F(n)
x1 = F(n+1)
So x2 = F(n+2) and x1 = F(n+1).
Together with the associativity of matrix multiplication, this means:
\|F(n+2)| |1 1| |F(n+1)| |1 1| |1 1| |F(n) | |1 1|^n |F(2)|
\|F(n+1)| = |1 0| x |F(n) | = |1 0| x |1 0| x |F(n-1)| = ... = |1 0| x |F(1)|
Take advantage of this to write a function which computes the nth Fibonacci number
with O(log n) multiplications.
Compare with the solution for Problems.P29.
-}
fibonacci' :: Int -> Int
fibonacci' n
| n <= 2 = n - 1
| otherwise = head $ head $ go (n - 2)
where
go i
| i == 1 = xs
| even i = mmult ys ys
| otherwise = mmult xs $ mmult ys ys
where
xs = [[1, 1], [1, 0]]
ys = go (i `div` 2)
Loading

0 comments on commit 84b5275

Please sign in to comment.