【发布时间】:2016-02-14 14:02:55
【问题描述】:
我一直在努力及时完成关于hackerrank 的this 练习。 但是由于超时,我的以下 Haskell 解决方案在测试用例 13 到 15 上失败了。
我的 Haskell 解决方案
import Data.Vector(Vector(..),fromList,(!),(//),toList)
import Data.Vector.Mutable
import qualified Data.Vector as V
import Data.ByteString.Lazy.Char8 (ByteString(..))
import qualified Data.ByteString.Lazy.Char8 as L
import Data.ByteString.Lazy.Builder
import Data.Maybe
import Control.Applicative
import Data.Monoid
import Prelude hiding (length)
readInt' = fst . fromJust . L.readInt
toB [] = mempty
toB (x:xs) = string8 (show x) <> string8 " " <> toB xs
main = do
[firstLine, secondLine] <- L.lines <$> L.getContents
let [n,k] = map readInt' $ L.words firstLine
let xs = largestPermutation n k $ fromList $ map readInt' $ Prelude.take n $ L.words secondLine
L.putStrLn $ toLazyByteString $ toB $ toList xs
largestPermutation n k v
| i >= l || k == 0 = v
| n == x = largestPermutation (n-1) k v
| otherwise = largestPermutation (n-1) (k-1) (replaceOne n x (i+1) (V.modify (\v' -> write v' i n) v))
where l = V.length v
i = l - n
x = v!i
replaceOne n x i v
| n == h = V.modify (\v' -> write v' i x ) v
| otherwise = replaceOne n x (i+1) v
where h = v!i
我发现的最佳解决方案会不断更新 2 个数组。一个数组作为主要目标,另一个数组用于快速索引查找。
更好的 Java 解决方案
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int k = input.nextInt();
int[] a = new int[n];
int[] index = new int[n + 1];
for (int i = 0; i < n; i++) {
a[i] = input.nextInt();
index[a[i]] = i;
}
for (int i = 0; i < n && k > 0; i++) {
if (a[i] == n - i) {
continue;
}
a[index[n - i]] = a[i];
index[a[i]] = index[n - i];
a[i] = n - i;
index[n - i] = i;
k--;
}
for (int i = 0; i < n; i++) {
System.out.print(a[i] + " ");
}
}
我的问题是
- 这个算法在 Haskell 中的优雅和快速实现是什么?
- 有没有比 Java 解决方案更快的方法来解决这个问题?
- 我应该如何在 Haskell 中优雅而高效地处理繁重的数组更新?
【问题讨论】:
-
请输入签名...
-
只是想知道您的 Java 解决方案是否通过了现场所有时间的平板测试?
-
@leftaroundabout 抱歉。缺少类型签名是否会降低可读性?我认为更少的代码 = 更具可读性,我很傻。
-
是的,但类型签名的作用至少与代码一样多。
-
没有类型签名真的很难阅读代码。
标签: arrays algorithm haskell mutable