Алгоритм поиска списка заданного точечного продукта и другого списка
Мне нужно написать функцию findL
который берет список L1 целых чисел и искомое произведение n и возвращает список L2 неотрицательных целых чисел, такой что L1 · L2 = n. (Под "точечным произведением" я подразумеваю сумму попарных произведений; например, [1,2] · [3,4] = 1·3+2·4 = 11.)
Так, например, findL(11, [1,2])
может вернуться SOME [3,4]
, Если нет возможного списка, я вернусь NONE
,
Я использую функциональный язык. (Конкретно Standard ML, но точный язык не так важен, я просто пытаюсь придумать алгоритм FP.) То, что я написал до сих пор:
Допустим, у меня есть findL(n, L1):
- если L1 = [], я возвращаю NONE.
- если L1 = [x] (список длины 1)
- если (n >= 0 и x > 0 и n mod x = 0), вернуть SOME [n div x]
- еще вернуть НЕТ
- Если длина L1 больше 1, я возвращаюсь к findL (n, L[1:]). Если это возвращает список L2, я возвращаю [1] сцепленный с L2. Если рекурсивный вызов возвращает NONE, я сделал еще один рекурсивный вызов для findL (0, L[1:]) и добавил [n div x] к результату, если он не был NONE. Это работает на многих входах, но не на других.
Мне нужно изменить часть 3, но я не уверен, что у меня есть правильная идея. Буду признателен за любые советы!
1 ответ
Если вы не хотите сказать, что пустые списки во входных данных всегда плохие (даже n = 0 со списком []), я бы рекомендовал возвращать что-то другое для пустого списка в зависимости от того, достигли ли вы 0 в конце (все было вычтено) или нет, затем повторять при получении любого непустого списка, а не в специальном случае списка из одного элемента.
Что касается третьего шага, вам нужно протестировать каждое возможное положительное целое число, кратное первому элементу вашего списка ввода, пока они не превысят n, а не только первый и последний. Первое полученное значение, отличное от None, достаточно хорошее, поэтому вы просто добавляете множитель (не кратный) к списку возврата. Если все дает вам Nones, вы возвращаете None.
Я не знаю SML, но вот как я это сделаю в Haskell:
import Data.Maybe (isJust, listToMaybe)
-- Find linear combinations of positive integers
solve :: Integer -> [Integer] -> Maybe [Integer]
-- If we've made it to the end with zero left, good!
solve 0 [] = Just []
-- Otherwise, this way isn't the way to go.
solve _ [] = Nothing
-- If one of the elements of the input list is zero, just multiply that element by one.
solve n (0:xs) = case solve n xs of
Nothing -> Nothing
Just ys -> Just (1:ys)
solve n (x:xs) = listToMaybe -- take first solution if it exists
. map (\ (m, Just ys) -> m:ys) -- put multiplier at front of list
. filter (isJust . snd) -- remove nonsolutions
. zip [1 ..] -- tuple in the multiplier
. map (\ m -> solve (n - m) xs) -- use each multiple
$ [x, x + x .. n] -- the multiples of x up to n
Вот это решение 11
с [1, 2]
а также 1
с [1, 2]
,