我正在学习Haskell和FP,并认为这是一个有趣的尝试和解决的问题。我尝试的算法是使用quickselect的变体来计算在枢轴上分割的两个子列表的长度,如果长度差异是1,则使用sums方法的差异来找到缺失的数字。如果大于1,那么我递归地钻入子列表。
我觉得我在这里非常接近一个有效的解决方案,但有一些边缘情况似乎不能很好地运作。在n小于100的情况下,我有时会看到某些丢失的数字,这些数字似乎是随机丢失的,当n与k缺失的数字相比足够小时,我有时会得到运行时异常。对于大的n组,这看似正确。我必须遗漏一些简单的东西。
有什么想法?我错过了一个简单的守卫?
findMissingNumber :: (Ord k, Integral k, Enum k) => [k] -> [k]
findMissingNumber [] = []
findMissingNumber xs = ( sum' [(head xs)..(last xs)] - sum' xs ) : []
findMissingNumbs :: [Int] -> [Int]
findMissingNumbs [] = []
findMissingNumbs xs =
let shouldBeLength = length [(head xs)..(last xs)]
pivot = round $ fromIntegral (shouldBeLength) / 2
pivotValue = xs !! (pivot - 1)
lower = filter (< pivotValue) xs
upper = filter (>= pivotValue) xs
lowerMissingCount
| lower == [] = 0
| (length lower) == 1 = 0
| otherwise = (length [(head lower)..(last lower)]) - (length lower)
upperMissingCount
| upper == [] = 0
| (length upper) == 1 = 0
| otherwise = (length [(head upper)..(last upper)]) - (length upper)
missingLowerValues
| (lowerMissingCount) == 1 = findMissingNumber (lower)
| (lowerMissingCount) > 1 = findMissingNumbs (lower)
| (lowerMissingCount) == 0 = []
| otherwise = []
missingUpperValues
| (upperMissingCount) == 1 = findMissingNumber (upper)
| (upperMissingCount) > 1 = findMissingNumbs (upper)
| (upperMissingCount) == 0 = []
| otherwise = []
in
missingLowerValues ++ [] ++ missingUpperValues
sum' :: (Num k) => [k] -> k
sum' xs = foldl' (+) 0 xs
main = do
putStrLn "Enter a list size: "
listSize <- readLn
intToRemove <- sequence $ replicate 5 $ randomRIO (1, (listSize :: Int))
putStrLn $ "Int to remove is: " ++ show intToRemove
let defaultList = [1..(listSize :: Int)]
let missingNumbers = findMissingNumbs $ (filter (not . (`elem` intToRemove)) defaultList)
putStrLn $ "The missing number is " ++ show missingNumbers