DrRacket - find the longest increasing subsequence - recursion

I want to create code for finding LIS. My code doesn't work very well. For example if the input is '(1 3 5 10 9 6 7), output should be '(1 3 5 6 7) but my program return '(1 3 5 10). What am I doing wrong? Have I code binary tree and then find the higher height? Or can I code this program in easiest way?
(define (return_sequence N lst)
(cond
[(empty? lst) '()]
[(< N (first lst)) (cons
(first lst)
(return_sequence (first lst) (rest lst))
)]
[else (return_sequence N (rest lst))]
)
)
(define (find_longest lst1 lst2)
(cond
[(empty? lst1) lst2]
[(empty? lst2) lst1]
[(< (length lst1) (length lst2)) lst2]
[else lst1]
)
)
(define (LIS lst)
(cond
[(empty? lst) '()]
[else (find_longest
(cons
(first lst)
(return_sequence (first lst) (rest lst)))
(LIS (rest lst))
)]
)
)

Before we begin, a question. Do you consider '(1 1) to be an increasing sequence? For now, I will assume you do not.
First, note that we can simplify find-longest as follows:
(define (find-longest lst1 lst2)
(if (<= (length lst1)
(length lst2))
lst1
lst2))
This is terribly inefficient, but we won't worry about that for now. It at least looks cleaner than your code.
I assume that you're trying to define (return_sequence N lst) to be the longest increasing subsequence of lst such that all elements of said subsequence are greater than N. I suggest you take a look at exactly what happens when you try (return_sequence 1 '(4 2 3)). We should expect the result to be '(2 3), but it is in fact '(4).
You need to think carefully about exactly how you want to handle the case where (< N (first lst)) and make sure you're not making a silly mistake (spoiler - you are making a silly mistake).
Edit: suppose that (< N (first lst)). The longest increasing subsequence of lst where all elements are greater than N either contains (first lst) or doesn't. To find the longest subsequence that doesn't, we compute (return_sequence N (rest lst)). To find the longest subsequence that does, we compute (cons (first lst) (return_sequence (first lst) (rest lst)). The relevant cond clause becomes
[(< N (first lst)) (find_longest
(cons (first lst)
(return_sequence (first lst) (rest lst)))
(return_sequence N (rest lst)))]
and this solves your problem.
On another note, it's extremely helpful to add in the value of minus-infinity, with the condition that this value is always less than any other value. In that case, we can just do
(define (LIS lst)
(return_sequence minus-infinity lst))
Doing this requires a little bit of cleverness, but it is possible.
In fact, one clever way to add minus_infinity is to pass into return_sequence not a number N, but the function (lambda (x) (< N x)). Then, instead of the line (< N (first list)), you would instead write (less_than_N (first list)). Then, you can (define (minus_infinity x) #t).
It's also possible to create a new symbol using gensym and have that be minus_infinity. You'd then want to do something rather cheeky like
(define minus_infinity (gensym))
(define (return_sequence N lst)
(let ((< (lambda (a b) (or (equal? a minus_infinity) (< a b)))))
cond ...)
(define (LIS lst)
(return_sequence minus_infinity lst))
with the cheeky bit being that we're not defining (<) recursively - the < that occurs in (lambda (a b) (or (equal? a minus_infinity) (< a b))) is the original <.
Finally, the algorithm you're trying is really slow. It's possible to solve this problem in O(n log n) where n = (length lst). Your solution will be an exponential time one, but improving it is highly nontrivial.

Related

Difficulty trying to take the n-th root of a product of n numbers

I'm trying to make a recursive function which takes in a list of n numbers. What this function should do is take the product of the n numbers and then take the nth root. I got the product of the n numbers working but do not know how to implement the nth root.
What I tried doing is implementing the expt x y function but could not get it right in the recursion. Moreover, when trying to implement this function, I also don't know how I will be able to feed the expt function the nth root. (y=1/n).
(define (nth-root-of-product-of-numbers lst)
(cond [(empty? lst) 1]
[else (* (first lst) (nth-root-of-product-of-numbers (rest lst)))]))
So, the above code produces the product on the list of n-numbers correctly, however it does not compensate for the n-th root problem. A sample input would be:
(check-within
(nth-root-of-product-of-numbers (cons 9 (cons 14 (cons 2 empty)))) 6.316359598 0.0001)
You need to calculate the nth-root at the end of the recursion. There are several ways to do this - for example, defining a helper procedure for finding the product and taking the root after calculating it:
(define (nth-root-of-product-of-numbers lst)
(define (product lst)
(cond [(empty? lst) 1]
[else (* (first lst) (product (rest lst)))]))
(expt (product lst) (/ 1 (length lst))))
A more efficient solution would be to write a tail-recursive procedure, and to pass along the number of elements to avoid calculating the length at the end. Here's how, using a named let:
(define (nth-root-of-product-of-numbers lst)
(let loop ((lst lst) (acc 1) (n 0))
(cond [(empty? lst)
(expt acc (/ 1 n))]
[else
(loop (rest lst) (* (first lst) acc) (add1 n))])))
An even more idiomatic solution would be to use built-in procedures to calculate the product:
(define (nth-root-of-product-of-numbers lst)
(expt (apply * lst) (/ 1 (length lst))))
Anyway, it works as expected:
(nth-root-of-product-of-numbers (list 9 14 2))
=> 6.316359597656378

Check for ascending order of a list in Racket

I'm new to racket and trying to write a function that checks if a list is in strictly ascending order.
'( 1 2 3) would return true
'(1 1 2) would return false (repeats)
'(3 2 4) would return false
My code so far is:
Image of code
(define (ascending? 'list)
(if (or (empty? list) (= (length 'list) 1)) true
(if (> first (first (rest list))) false
(ascending? (rest list)))))
I'm trying to call ascending? recursively where my base case is that the list is empty or has only 1 element (then trivially ascending).
I keep getting an error message when I use check-expect that says "application: not a procedure."
I guess you want to implement a procedure from scratch, and Alexander's answer is spot-on. But in true functional programming style, you should try to reuse existing procedures to write the solution. This is what I mean:
(define (ascending? lst)
(apply < lst))
It's shorter, simpler and easier to understand. And it works as expected!
(ascending? '(1 2 3))
=> #t
(ascending? '(1 1 2))
=> #f
Some things to consider when writing functions:
Avoid using built in functions as variable names. For example, list is a built in procedure that returns a newly allocated list, so don't use it as an argument to your function, or as a variable. A common convention/alternative is to use lst as a variable name for lists, so you could have (define (ascending? lst) ...).
Don't quote your variable names. For example, you would have (define lst '(1 2 3 ...)) and not (define 'lst '(1 2 3 ...)).
If you have multiple conditions to test (ie. more than 2), it may be cleaner to use cond rather than nesting multiple if statements.
To fix your implementation of ascending? (after replacing 'list), note on line 3 where you have (> first (first (rest list))). Here you are comparing first with (first (rest list)), but what you really want is to compare (first lst) with (first (rest lst)), so it should be (>= (first lst) (first (rest lst))).
Here is a sample implementation:
(define (ascending? lst)
(cond
[(null? lst) #t]
[(null? (cdr lst)) #t]
[(>= (car lst) (cadr lst)) #f]
[else
(ascending? (cdr lst))]))
or if you want to use first/rest and true/false you can do:
(define (ascending? lst)
(cond
[(empty? lst) true]
[(empty? (rest lst)) true]
[(>= (first lst) (first (rest lst))) false]
[else
(ascending? (rest lst))]))
For example,
> (ascending? '(1 2 3))
#t
> (ascending? '(1 1 2))
#f
> (ascending? '(3 2 4))
#f
If you write down the properties of an ascending list in bullet form;
An ascending list is either
the empty list, or
a one-element list, or
a list where
the first element is smaller than the second element, and
the tail of the list is ascending
you can wind up with a pretty straight translation:
(define (ascending? ls)
(or (null? ls)
(null? (rest ls))
(and (< (first ls) (first (rest ls)))
(ascending? (rest ls)))))
This Scheme solution uses an explicitly recursive named let and memoization:
(define (ascending? xs)
(if (null? xs) #t ; Edge case: empty list
(let asc? ((x (car xs)) ; Named `let`
(xs' (cdr xs)) )
(if (null? xs') #t
(let ((x' (car xs'))) ; Memoization of `(car xs)`
(if (< x x')
(asc? x' (cdr xs')) ; Tail recursion
#f)))))) ; Short-circuit termination
(display
(ascending?
(list 1 1 2) )) ; `#f`

Sum of values in a list squared in Scheme

I'm trying to have the following program work, but for some reason it keeps telling me that my input doesnt contain the correct amount of arguments, why? here is the program
(define (sum f lst)
(cond
((null? lst)
0)
((pair? (car lst))
(+(f(sum (f car lst))) (f(sum (f cdr lst)))))
(else
(+ (f(car lst)) (f(sum (f cdr lst)))))))
and here is my input: (sum (lambda (x) (* x x)) '(1 2 3))
Thanks!
btw I take no credit for the code, Im just having fun with this one (http://groups.engin.umd.umich.edu/CIS/course.des/cis400/scheme/listsum.htm)
You're indeed passing the wrong number of arguments to the procedures sum and f, notice that the expressions (sum (f car lst)), (sum (f cdr lst)) are wrong, surely you meant (sum f (car lst)), (sum f (cdr lst)) - you don't want to apply f (a single-parameter procedure) to the two parameters that you're passing, and sum expects two arguments, but only one is passed. Try this instead:
(define (sum f lst)
(cond ((null? lst)
0)
((pair? (car lst))
(+ (sum f (car lst)) (sum f (cdr lst))))
(else
(+ (f (car lst)) (sum f (cdr lst))))))
More important: you're calling the f procedure in the wrong places. Only one call is needed in the last line, for the case when (car lst) is just a number and not a list - in the other places, both (car lst) and (cdr lst) are lists that need to be traversed; simply pass f around as a parameter taking care of correctly advancing the recursion.
Let's try the corrected procedure with a more interesting input - as it is, the procedure is capable of finding the sum of a list of arbitrarily nested lists:
(sum (lambda (x) (* x x)) '(1 (2) (3 (4)) 5))
> 55
You should take a look at either The Little Schemer or How to Design Programs, both books will teach you how to structure the solution for this kind of recursive problems over lists of lists.

Scheme sum of list

First off, this is homework, but I am simply looking for a hint or pseudocode on how to do this.
I need to sum all the items in the list, using recursion. However, it needs to return the empty set if it encounters something in the list that is not a number. Here is my attempt:
(DEFINE sum-list
(LAMBDA (lst)
(IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
'()
(+
(CAR lst)
(sum-list (CDR lst))
)
)
)
)
This fails because it can't add the empty set to something else. Normally I would just return 0 if its not a number and keep processing the list.
I suggest you use and return an accumulator for storing the sum; if you find a non-number while traversing the list you can return the empty list immediately, otherwise the recursion continues until the list is exhausted.
Something along these lines (fill in the blanks!):
(define sum-list
(lambda (lst acc)
(cond ((null? lst) ???)
((not (number? (car lst))) ???)
(else (sum-list (cdr lst) ???)))))
(sum-list '(1 2 3 4 5) 0)
> 15
(sum-list '(1 2 x 4 5) 0)
> ()
I'd go for this:
(define (mysum lst)
(let loop ((lst lst) (accum 0))
(cond
((empty? lst) accum)
((not (number? (car lst))) '())
(else (loop (cdr lst) (+ accum (car lst)))))))
Your issue is that you need to use cond, not if - there are three possible branches that you need to consider. The first is if you run into a non-number, the second is when you run into the end of the list, and the third is when you need to recurse to the next element of the list. The first issue is that you are combining the non-number case and the empty-list case, which need to return different values. The recursive case is mostly correct, but you will have to check the return value, since the recursive call can return an empty list.
Because I'm not smart enough to figure out how to do this in one function, let's be painfully explicit:
#lang racket
; This checks the entire list for numericness
(define is-numeric-list?
(lambda (lst)
(cond
((null? lst) true)
((not (number? (car lst))) false)
(else (is-numeric-list? (cdr lst))))))
; This naively sums the list, and will fail if there are problems
(define sum-list-naive
(lambda (lst)
(cond
((null? lst) 0)
(else (+ (car lst) (sum-list-naive (cdr lst)))))))
; This is a smarter sum-list that first checks numericness, and then
; calls the naive version. Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum. Oscar's accumulator version is better!
(define sum-list
(lambda (lst)
(cond
((is-numeric-list? lst) (sum-list-naive lst))
(else '()))))
(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))
(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
Output:
Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
>
I suspect your homework is expecting something more academic though.
Try making a "is-any-nonnumeric" function (using recursion); then you just (or (is-any-numeric list) (sum list)) tomfoolery.

Overloaded function failing giving Compiler recursion error

With the following code, I get #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position (NO_SOURCE_FILE:4)> despite the fact that all recurs are in tail positions. If I remove the recur from the one-argument version, it stops complaining. Why is this happening?
(defn remove-duplicates "Removes duplicate elements of lst.
For example, given (1 2 3 1 4 1 2), remove-duplicates returns a sequence
containing the elements (1 2 3 4), in some order."
[lst] (recur (rest lst) (set (first lst)))
[lst uniques] (cond (zero? (count lst)) uniques
:else (cond
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (first lst)))))
You haven't split up the multi-arity bodies right. Should read (defn foo ([x] (...)) ([x y] (...))). This causes the compiler to think you're doing totally different stuff, which probably accounts for your issue.
First of all: you know that all you want is (def remove-duplicates set) or -- if you want a vector -- (def remove-duplicates-vec (comp vec set)), right?
Five things here:
As amalloy noticed, you should've added parens
As kotarak noticed, you can't recur between arities
You can't call (set (first lst)) because set wants coll. If you want, do something like (set (vector (first [1 2 3 2 3]))) but this is neither pretty nor idiomatic
Doing (cond pred1 code1 :else (cond pred2a code2a :else code2b)) could be made simplier: (cond pred1 code1 pred2a code2a :else code2b) -- what you did is treated cond macro as if it were if (which is a built-in as far as I know)
Your last tail-call is also wrong. Assume we've started with [1 2 3 2 1]
When you call it first you have following arguments: ([2 3 2 1] #{1}) (I've skipped the boring part)
Then you have last predicate true, so you go with ([3 2 1] 2) and this is obviously wrong because you wanted ([3 2 1] #{1 2}). You probably want to call (recur (rest lst) (conj uniques (first lst)))
Summing up:
(defn remove-duplicates
([lst] (remove-duplicates (rest lst) #{(first coll)}))
([lst uniques]
(cond
(zero? (count lst)) uniques
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (conj uniques (first lst))))))

Resources