我不确定我在编写scala代码时是否犯了错误。
问题是:
The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.
73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450
Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product? 博主(http://www.ituring.com.cn/article/111574)表示,他由haskell编写的代码只使用6ms:
import Data.List
import Data.Char
main = do
a <- readFile "008.txt"
print . maximum . map (product . take 13) . tails $ map digitToInt $ filter isDigit a 因此,我尝试使用scala:
object Main {
def main(args: Array[String]): Unit = {
val begin: Long = System.currentTimeMillis()
val content = Source.fromFile("file/text").filter(_.isDigit).map(_.toInt - '0').toList
val lists =
for (i <- 0 to content.size - 13)
yield content.drop(i).take(13)
println(lists.maxBy(_.reduce(_ * _)))
val end: Long = System.currentTimeMillis()
println(end - begin)
}
} 但这需要120ms的平均时间,我认为问题是I/O,但我发现它只占用了10ms(我尝试使用FileChannel而不是Source,但它并没有节省太多时间),.It是map和flatmap(for)操作,花费的时间最多。
然后,我尝试使用java来查看原因是否是JVM。不足为奇的是,java版本运行了很多faster.Just关于20ms的内容:
public static void main(String[] args) throws IOException {
long begin = System.currentTimeMillis();
byte[] bytes = Files.readAllBytes(Paths.get("file/text"));
List<Integer> list=new ArrayList<>();
for(int i=0;i<bytes.length;i++){
if(bytes[i]-'0'>=0&&bytes[i]-'0'<=9) list.add(bytes[i]-'0');
}
int max=-1;
List<Integer> maxList=new ArrayList<>();
List<Integer> temp=new ArrayList<>();
for(int i=0;i<=list.size()-13;i++){
int value=1;
for(int j=i;j<i+13;j++){
temp.add(list.get(j));
value*=list.get(j);
}
if(value > max) {
max = value;
maxList.clear();
maxList.addAll(temp);
}
temp.clear();
}
System.out.println(maxList);
long end = System.currentTimeMillis();
System.out.println(end - begin);
} 我的问题是为什么scala版本的代码运行这么慢?
发布于 2014-05-31 02:41:05
正如@etherous提到的:在Java版本中使用可变状态,而Scala版本是完全不可变的,而且编写效率更低。他们只是不一样。
您可以尝试避免maxBy,也可以尝试在一次迭代中保存已经计算过的结果。这个应该更接近您的Java版本。
val content = Source.fromFile("file/text").filter(_.isDigit).map(_.toLong - '0').toList
val result = (0 to content.size - 13).foldLeft((List.empty[Long], -1l)){case (current @(_, curMax), next) => {
val temp = content.drop(next).take(13)
val tempVal = temp.reduce(_*_)
if(tempVal > curMax) (temp, tempVal) else current
}
}result是这里的一个元组,它包含了_1的十三个数字的列表,它的产品是_2,就像你想两者都想要的那样。
奖金
现在我已经考虑过了。有一种名为sliding的方法精确地处理了这个问题。但我想它的运行速度跟你的scala代码一样慢。至少这将是简短的:)。
content.sliding(13).maxBy(_.reduce(_*_))发布于 2014-05-31 03:15:21
scala版本运行缓慢,因为您正在传递大量函数并创建许多中间对象。haskell版本是快速的,因为它是围绕这些成语构建的,而不是scala,scala被黑客入侵了JVM。如果像编写java那样编写scala (对于我来说是20 as,与java相同),那么scala中的性能是相当的:
import scala.collection.mutable.ArrayBuffer
val begin = System.currentTimeMillis()
val buf = new ArrayBuffer[Int]()
val test = "73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450"
val d = test.toCharArray
var i = 0
while (i != d.length) {
val c = d(i) - '0'
if (c >= 0 && c <= 9) {
buf += c
}
i += 1
}
i = 0
var max = 0
var maxStart = 0
while (i != buf.length - 13) {
val test = buf(i) * buf(i + 1) * buf(i + 2) * buf(i + 3) * buf(i +4) * buf(i + 5) * buf(i + 6) * buf(i + 7) * buf(i + 8)* buf(i + 9)* buf(i + 10)* buf(i + 11)* buf(i + 12)
if (test > max){
max = test
maxStart = i
}
i += 1
}
System.out.println(buf.slice(maxStart, maxStart + 13))
val end = System.currentTimeMillis()
println(end - begin)打印出来:
ArrayBuffer(9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7)
20更新
看来JVM可以对其进行相当多的优化,经过50次迭代后,这个值可降到1ms:
object Main extends App {
(1 until 50).foreach(i => {
val begin = System.currentTimeMillis()
val max = Source.fromFile("file/text")
.toList
.filter(_.isDigit)
.map(_.toInt - '0')
.sliding(13)
.maxBy(_.reduce(_ * _))
println(max)
val end = System.currentTimeMillis()
println(end - begin)
})
}指纹:
List(9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7)
144
...
List(9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7)
1发布于 2014-09-02 09:43:40
还有一个变体,只是为了好玩。它不会一蹴而就将字符串转换为Long列表。在控制台18毫秒。
def findMax(startTime:Long, maxStretch:List[Long], currentStretch:List[Long], longLine:String, currentProd:Long):(List[Long], Long, Long) =
longLine match {
case "" => (maxStretch, maxStretch.product, System.currentTimeMillis - startTime)
case _ => {
val nextElement = longLine(0)
val lastElement = currentStretch(0)
val nextStretch = currentStretch.tail ++ List(nextElement.toLong-'0'.toLong)
val nextProd = nextStretch.product
val (nextMaxStretch, nextMaxProd) = if(nextProd>currentProd) {(nextStretch, nextProd)} else (maxStretch, currentProd)
findMax(startTime,nextMaxStretch, nextStretch, longLine.substring(1),nextMaxProd)
}
}
val strContent = <long string>.replaceAll(" ","")
val start = strContent.take(13).map(_.toLong-'0'.toLong).toList
scala> findMax(System.currentTimeMillis, start, start, strContent.drop(13), start.product)
res47: (List[Long], Long, Long) = (List(5, 5, 7, 6, 6, 8, 9, 6, 6, 4, 8, 9, 5),23514624000,18)https://stackoverflow.com/questions/23965737
复制相似问题