2015-07-10 17 views
7

İzlediğim herehızlı giriş tarama

bulunabilir SPOJ soruyu çözmek için çalışılıyor benim çözümdür. Buradaki sorun, SPOJ'da çalıştırdığım zaman aşımı olduğudur.

Sadece fmt.Scan kullanıyordum, ancak daha hızlı giriş taraması yapmak yerine bufio kullanıyorum öneren this iş parçacığıyla karşılaştım.

Yine de zaman aşımı sorunu yaşıyorum. Sadece bütün girdileri elde etmek için döngü yapıyorum ve bu döngü içinde girdinin bölünebilir olup olmadığını belirliyorum. Bu yüzden, onun döngü değil, zaman alan girdi taraması olduğuna inanıyorum. Girişi daha hızlı okumak için bunu nasıl geliştirebilirim? Yoksa sorun başka bir yer mi?

cevap

5

Sen girişten satırları okumak için bufio.Scanner kullanabilirsiniz.

Ve her zaman rakamları okuduğumuzdan, numarayı almak için yüksek düzeyde optimize edilmiş bir dönüştürücü oluşturabiliriz. string'u oluşturan Scanner.Text()'u kullanmaktan kaçınmalıyız, çünkü bu numarayı Scanner.Bytes() tarafından döndürülen ham bayttan elde edebilirsiniz. Scanner.Text(), Scanner.Bytes() ile aynı belirteci döndürür ancak ilk olarak string'a dönüşür; bu, açıkça daha yavaştır ve "çöp" üretir ve gc için çalışır. []byte ondalık formatının dize temsilinin UTF-8 kodlu bayt dizisi içerdiğinden

func toInt(buf []byte) (n int) { 
    for _, v := range buf { 
     n = n*10 + int(v-'0') 
    } 
    return 
} 

Bu toInt() eser: Yani burada

çiğ baytlarından bir int elde eden bir dönüştürücü fonksiyonudur UTF-8 kodlu baytları bire bir eşleştirilen '0'..'9' aralığında sadece rakam içeren sayıdır (bir basamak için bir bayt kullanılır). '0' -> 48, '1' -> 49 vb

Bu tam uygulamayı kullanarak::

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
) 

func main() { 
    var n, k, c int 
    scanner := bufio.NewScanner(os.Stdin) 

    scanner.Scan() 
    fmt.Sscanf(scanner.Text(), "%d %d", &n, &k) 

    for ;n > 0; n-- { 
     scanner.Scan() 
     if toInt(scanner.Bytes())%k == 0 { 
      c++ 
     } 
    } 

    fmt.Println(c) 
} 

func toInt(buf []byte) (n int) { 
    for _, v := range buf { 
     n = n*10 + int(v-'0') 
    } 
    return 
} 

Bu çözüm, örneğin strconv.Atoi() arayarak yaklaşık 4 kat daha hızlıdır byte basamaklar arasında eşleme sadece bir değişimdir.

Notlar: Ben girdi geçerlidir varsayılır Yukarıdaki çözümde

, bu her zaman geçerli numarası içeriyor (bize n ve k veren) ilk sonra en az n satır içeriyor olduğunu.

giriş n+1 satırdan sonra kapanırsa, biz kullanabilirsiniz basitleştirilmiş for (ve hatta azaltma ve n güvenmek gerekmez): Bu kadar iyi çalışır

for scanner.Scan() { 
    if toInt(scanner.Bytes())%k == 0 { 
     c++ 
    } 
} 
+0

Tarama girişi nasıl durdurulur? 'scanner.Scan()' döngüsü sadece giriş tuşu – callmekatootie

+0

@callmekatootie 'scanner.Scan()' tuşuna bastığımda bile giriş devam edene kadar devam eder. Yerel olarak test etmek isterseniz, hatları sayan değiştirilmiş bir döngü kullanın. Düzenlenmiş cevaba bakınız. – icza

+0

Tamam. Girdi sayısı olan n 'değişkeni. Öyleyse, eğer n girdilerden sonra durmam gerekiyorsa, 'n' 0 'koşulu için koşulunu değiştiririm ve' scanner.Scan() 'işlevini döngü için – callmekatootie

1

deneyin (Bahsettiğiniz iplik önerildiği gibi) bufio.Scanner kullanılarak:

fmt.Scan(&n) 
fmt.Scan(&k) 

scanner := bufio.NewScanner(os.Stdin) 
for n > 0 { 
    scanner.Scan() 
    k, _ := strconv.Atoi(scanner.Text()) 
    ... 
+0

.Ancak, alınan süre 1.08 saniyedir. Diğer çözüm kabul edildi çünkü 0.28 saniye sürdü. – callmekatootie

+0

@callmekatootie, evet anlamlıdır. scanner.Text() 'bellek ayırır ve çözümden daha yavaş bir şekilde yapar. @icza – kostya

İlgili konular