2012年5月31日木曜日

TopCoder SRM393 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

道を安全なものにするために、ある地域の政府は時間によって複数の速度制限を設けることにした。混雑時には危険な事故を避けるため、速度制限は厳しいものになる。あなたは、ある単位距離だけ運転する必要があり、どの程度の時間がかかるか知りたいと思っている。問題では、速度制限を意味するspeedLimit[]という整数型の配列が与えられる。(0を基準とした添え字で)要素iの内容はある時刻iからi+1の単位時間における速度制限である。speedLimit[]は1日の速度制限の様子を表しており、このパターンは繰り返されることになる(1日経過して速度制限の内容は配列の先頭に戻る)。あなたは時刻0から運転を開始するものとし、運転中は速度制限の上限で常に運転を行うものとする。journeyLengthという距離だけ走った時の、運転の平均速度を返すメソッドを作成せよ。

私の解答はこちら。

public class VariableSpeedLimit {

 public double journeyTime(int journeyLength, int[] speedLimit) {
  int idx = 0; // 走っている時点での速度制限配列の添字管理
  double time = 0.0; // 走行時間
  int patternLength = speedLimit.length;
  int totalRun = 0;
  while( true ){
   if( totalRun + speedLimit[idx] < journeyLength ){ // 次の単位時間も継続して走る場合
    totalRun += speedLimit[idx];
    time += 1.0;
   }else{ // 次の単位時間中に走り終える場合
    time += (journeyLength - totalRun)*1.0 / speedLimit[idx];
    break;
   }
   idx = (idx + 1) % patternLength; / 速度制限の上限値を変更する
  }
  return time;
 }

}

得点は233.63/250、1回のsubmitでシステムテストクリア。中央値は約187点。

2012年5月30日水曜日

初めてのコンピュータサイエンス第10章解答

第10章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。

  • pythonにおけるリストのコピーはList[:]のように、全体をスライシングする書き方にすればよい。

1

a)b)の解答

空の文字列を用意して、AであればT、TであればA、GであればC、CであればGを結合することを文字列の末尾まで続ける。

c)の解答

def complement(sequence):
    ret = ''
    for c in sequence:
        if c == 'A':
            ret += 'T'
        elif c == 'T':
            ret += 'A'
        elif c == 'G':
            ret += 'C'
        elif c == 'C':
            ret += 'G'

    return ret

if __name__ == '__main__':
    print complement('AATTGCCGT')

2

a)~c)までまとめて解答。a)の解答はmin_index関数の内部そのものになります。また、引数にboolというものを取れいう指示があるのですが、boolは予約語なので、booleanに変更。

def min_index(sequence):
    idx = 1
    val = sequence[0]
    for i in range(2, len(sequence)):
        if sequence[i] < val:
            val = sequence[i]
            idx = i
    return tuple((val, idx))

def max_index(sequence):
    idx = 1
    val = sequence[0]
    for i in range(2, len(sequence)):
        if sequence[i] > val:
            val = sequence[i]
            idx = i
    return tuple((val, idx))

def min_or_max_index(sequence, boolean):
    if boolean == True:
        return max_index(sequence)
    else:
        return min_index(sequence)

if __name__ == '__main__':
    data = [3, 7, 2, 0, 23.1, 1.4, 9]
    print min_index(data)
    print min_or_max_index(data, False)
    print min_or_max_index(data, True)

3

どこまでを仕様とするかにも依るが、面白いリストには、例えば長さ0や長さ1のリスト、最小値が先頭にあるリスト、文字列を含むリストというのも考えられる。最小値が先頭にある場合は、初期設定で最小値を先頭の値としている場合に対応するためのテストである。以下のコードでは、前提として、長さが1以上、文字列は一切含まないものとしてテストを行うものである。ex10_2は2番のコードである。

import nose
from ex10_2 import min_index

def test_min_index():
    data = [1, 100]
    assert min_index(data) == tuple((1, 0))
    data = [3]
    assert min_index(data) == tuple((3, 0))

if __name__ == '__main__':
    test_min_index()

4

最小の2つの要素を探すのに、0または1つの要素からなるリストを与えられた場合は、そのようなものは「ない」ということで、Noneを返す。もしくは添字アクセスに失敗することから、例外を返すというのが考えられる。はじめの先頭2要素の比較で、アクセスしようとしている添字が存在していないことが問題になることに注意。

2012年5月29日火曜日

初めてのコンピュータサイエンス第9章解答

第9章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。

  • setオブジェクトで保持される順序にルールはない。
  • 集合はハッシュテーブルというデータ構造に格納される。
  • 集合の要素に対し、ハッシュコードが計算される。ハッシュコードはイミュータブル(書き換え不可能なデータ)のみ持つことが許される。
  • 辞書の初期化は{}で行う。追加はappendなどではなく、辞書名[キー] = 値 という形式で指定すればOK。
  • 185ページのdict_of_dicts.pyのサンプルコードに登場する辞書でJグドールに関する項目に'霊長類研究者'(英語では'primate researcher')とあるが、この後ろに「,」がないため、編集の必要がある。おそらくバグ。

1

# -*- encoding: sjis -*-

def find_dups(data):
    h_table = {}
    for d in data:
        if d in h_table.keys(): # getメソッドを利用する方法もある
            h_table[d] += 1
        else:
            h_table[d] = 1
    ret = []
    # iteritemsはオブジェクトのコピーを作らないので高速に動かすことができる
    for (key, value) in h_table.iteritems():
        if value >= 2:
            ret.append(key)
    return ret

if __name__ == '__main__':
    data = range(10) + range(10, 5, -1) + range(3, 7)
    ret = find_dups(data)
    print ret

2

def mating_pairs(males, females):
    ''' the size of males and that of females are the same. '''
    ret = []
    # while males: is OK. this answer is a bit copmlex.
    while len(males) > 0:
        ret.append((males.pop(), females.pop()))
    return set(ret)

if __name__ == '__main__':
    males = set(['A', 'B', 'C', 'D', 'E'])
    females = set(['1', '2', '3', '4', '5'])
    print mating_pairs(males, females)

3

PDB形式のAUTHORの行に関する情報はこちらのpdfを参考にするとよいでしょう。人物名はコンマ区切り、AUTHORと人名は空白で区切られているという条件を使います。また、最後にコンマがあり人名が続かないこともありますので、そのようなことも考慮しています。

# -*- encoding: sjis -*-

import sys

def read_author(r):
    ret = set()
    for line in r:
        if not line:
            continue
        if line[:6].upper() != 'AUTHOR': # AuthorなどもOKにするため、upper()を挟んでいる
            continue
        # 仕様の都合上8文字目から作者名が始まる可能性がある。
        # strip()でいったん両端の空白を削除してから","で区切る
        line = line[7:].strip().split(",")
        print line
        for i in range(len(line)):
            if not line[i]: # AUTHORとあるが、何も続かない場合
                continue
            ret.add(line[i])
    return ret # setを返しておく

if __name__ == '__main__':
    names = set()
    for filename in sys.argv[1:]: # 外部からファイルを読み込みたい
        infile = open(filename, 'r')
        name = read_author(infile)
        names = names.union(name) # 和集合はunionである
        infile.close()
    print names

4(自信薄)

setの中に中身が変更可能なsetが入れられないのでfrozensetにして入れている。vowelは要素にfrozensetのデータを持つが、すでに通常のsetとして扱って問題ない。中身が書き換え可能なメモリアドレスにvowelsが配置されるということになる。

5

def count_values(dic):
    values = {}
    for (key, value) in dic.iteritems():
        if not value in values:
            values[value] = 1
    return len(values)

if __name__ == '__main__':
    print count_values({'red':1, 'green':2, 'blue':3})
    print count_values({'red':1, 'green':2, 'blue':1})
    print count_values({'red':2, 'green':2, 'blue':2})

6

def min_elementary_particle(dic):
    minimum = 1.1 # probability is always smaller than 1
    elem = ''
    for (key, value) in dic.iteritems():
        if value < minimum:
            minimum = value
            elem = key
    return elem

if __name__ == '__main__':
    component = {'neutrino':0.14 , 'neutron':0.55,
                 'proton':0.21, 'meson':0.03, 'muon':0.07}
    print min_elementary_particle(component)

7

def count_duplicates(dic):
    dup = {}
    for (key, value) in dic.iteritems():
        if not value in dup:
            dup[value] = 1
        else:
            dup[value] += 1

    dup_list = []
    for (key, value) in dup.iteritems():
        if value >= 2:
            dup_list.append(key)
    return len(dup_list)

if __name__ == '__main__':
    color = {'red':1, 'green':4, 'blue':2, 'orange':3, 'green':2, 'orange':6}
    print count_duplicates(color) # 2 is duplicated number.

8

例外という先の内容を無理やり利用しろということなので、試しに使ってみた。

def fetch_and_set(dic, key, new_value):
    if key in dic:
        old_value = dic[key]
        dic[key] = new_value
        return old_value
    else:
        raise KeyError("Unable to replace value for nonexistent key")

if __name__ == '__main__':
    color = {'red':1, 'green':4, 'blue':2, 'orange':3}
    print fetch_and_set(color, 'green', 100) # 4
    try:
        fetch_and_set(color, 'black', 3) # KeyError exception
    except KeyError:
        print "KeyError occurred!"

9

問題の仕様にはないのですが、辞書には必ずしもキーがR、G、Bだけではないものと仮定します。RGB以外は無視するものとします。

def is_balanced(dic):
    total = 0
    for (key, value) in dic.iteritems():
        if key == 'R' or key == 'G' or key == 'B':
            total += value

    if abs(total - 1.0) < 10 ** -15: # almost equal to 1
        return True
    else:
        return False

if __name__ == '__main__':
    color = {'R':0.1, 'G':0.4, 'B':0.5}
    print is_balanced(color) # True
    color = {'R':0.1, 'G':0.4, 'X':0.2, 'B':0.5}
    print is_balanced(color) # True
    color = {'R':0.1, 'G':0.4, 'B':0.2}
    print is_balanced(color) # False

10

両方の辞書に同じキーと同じ値が含まれている対のみ返します。同じキーだが値が違うという場合はdict_intersectの返り値の辞書には含まないものとします。

def dict_intersect(dic1, dic2):
    k2 = dic2.keys()
    ret = {}
    for (k1, v1) in dic1.iteritems():
        if k1 in k2 and v1 == dic2[k1]:
            ret[k1] = v1
    return ret

if __name__ == '__main__':
    c1 = {'red':1, 'green':4, 'blue':2, 'orange':3, 'green':2, 'orange':6}
    c2 = {'red':1, 'green':5, 'blue':2, 'yellow ':3}
    print dict_intersect(c1, c2) # blue and red are extracted

11

scientists = {
  'jgoodall'  : {'surname'  : 'Goodall',
                 'forename' : 'Jane',
                 'born'     : 1934,
                 'died'     : None,
                 'notes'    : 'primate researcher', # distributed sample code lacks comma.
                 'author'   : ['In the Shadow of Man', 'The Chimpanzees of Gombe']},
  'rfranklin' : {'surname'  : 'Franklin',
                 'forename' : 'Rosalind',
                 'born'     : 1920,
                 'died'     : 1957,
                 'notes'    : 'contributed to discovery of DNA'},
  'rcarson'  : {'surname'  : 'Carson',
                 'forename' : 'Rachel',
                 'born'     : 1907,
                 'died'     : 1964,
                 'notes'    : 'raised awareness of effects of DDT',
                 'author'   : ['Silent Spring']}
}

def db_headings(dic):
    ret = []
    for values in dic.values():
        ret += values.keys()
    return set(ret)

if __name__ == '__main__':
    print db_headings(scientists)

12

scientistsは上のデータを利用することにします。rfranklinは他の二つとキーが異なるため内部の辞書は常に一定にはなりません。そのため、db_consistent関数にscientistsを渡すと、Falseになります。if elem.symmetric_difference(set(values)):は要素数が0でなければという意味になります。

def db_consistent(dic):
    first = dic.keys()[0]
    elem = set(dic[first].keys())
    for values in dic.values():
        if elem.symmetric_difference(set(values)):
            return False
    return True

if __name__ == '__main__':
    print db_consistent(scientists)

13

空行で機能が大まかに区切られているので、それを1つのまとまりとしてモジュールにするというだけですね。

import sys

def create_dic(files):
    count = {}
    for filename in sys.argv[1:]:
        infile = open(filename, 'r')
        for line in infile:
            name = line.strip()
            count[name] = count.get(name, 0) + 1
        infile.close()
    return count

def reverse_dict(dic):
    freq = {}
    for (name, times) in dic.iteritems():
        print name, times
        if times in freq:
            freq[times].append(name)
        else:
            freq[times] = [name]
    return freq

def print_dic(dic):
    for key in sorted(dic):
        print key
        for name in dic[key]:
            print ' ', name

if __name__ == '__main__':
    dic = create_dic(sys.argv[1:])
    r_dic = reverse_dict(dic)
    print_dic(r_dic)

14

a)、b)の解答は以下の通り。

def sparse_add(dic1, dic2):
    ret = dic1.copy()
    keys = set(dic1.keys() + dic2.keys())
    for key in keys:
        ret[key] = 0
        if key in dic1.keys():
            ret[key] += dic1[key]
        if key in dic2.keys():
            ret[key] += dic2[key]
    return ret

def sparse_dot(dic1, dic2):
    ret = 0
    for (key, value) in dic1.iteritems():
        if key in dic2:
            ret += value * dic2[key]
    return ret

if __name__ == '__main__':
    v1 = {0:1, 6:3, 7:-1}
    v2 = {1:1, 2:2, 6:1, 7:-1}
    print sparse_add(v1, v2) # {0: 1, 1: 1, 2: 2, 6: 4, 7: -2}
    print sparse_dot(v1, v2) # 4

c)に関しては、疎ベクトルの長さが、辞書の長さになるのか、それとも最後に現れた辞書のキーの値+1になるのかということが曖昧になっている。0を値に持つキーをどのように扱うかということが、「疎ベクトルの長さ」という言葉だけでははっきりしないということである。

2012年5月28日月曜日

英単語学習記録20120528

英単語 意味
drop by立ち寄る
in low spirits意気消沈する
herd群れ、群衆、(群れを)集める
take charge of~の世話を引き受ける
portion部分、割り当て
compassion思いやり
nonethelessそれでもやはり
chronicle記録する
indispensable必須の、欠かせない
premise前提
troop部隊、群れ
crucial特に重要な
jargon専門用語、業界用語
endorse推薦する
string of一連の
official職員
appliance電化製品
perimeter周囲
congestion混雑
distribution流通、分布
vast広大な、膨大な
relocate~を移転する
dispatch発送する
in accordance with~~に従って
legitimate正当な
courteous礼儀正しい、丁寧な
excerpt抜粋
be up to~~を遂行することができる
rewardingやりがいのある
perplexed困った、途方に暮れた(be at a lossと同じ)
come up発生する(ariseと同じ)

2012年5月26日土曜日

初めてのコンピュータサイエンス第8章解答

第8章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。

  • ファイルを読み込む際は関数の外でファイルのオープン・クローズを行うとよい。これは処理を1つの関数だけで済ませることができるためである。Webページやストリームなどを統一的に扱える。
  • ファイルの追加はopenする際の引数に'a'と与える
  • pp.161の注釈は「単一のタプルが返されている」ではなく、「単一のリストが返される」が正しい。おそらく誤植。

1

後ろから前に向かってファイル全体を読み出すという意味をどう捉えるかが問題になりそうですが、行だけ後ろから前へと見るか、行の中身まで反転させるか悩ましいところではあります。今回は前者で考えています。

def read_reverse(file):
    rev = []
    for line in file:
        rev.insert(0, line)
    for line in rev:
        print line,

if __name__ == '__main__':
    f = open('data.txt', 'r')
    read_reverse(f)

2

タプルのタプルの方が扱いやすいのは、意味的なまとまりで区切っているためである。今回のコードでは、日付、緯度、経度、天気情報という意味でまとまっているので、データへのアクセスが単純化できる(経度は何番目だっけ?などと悩むことは減るだろう)。実は問題の解答がオライリーから提供されているが、誤りのように思われる。fieldsがタプルのタプルでないとループが適切に動かないためである。コード中の中で呼び出しているテキストファイルは提供されていないので、関数のコメントにある仕様に沿って作成する必要がある。

def read_weather_data(r):
    '''Read weather data from reader r in fixed-width format.
    The field widths are:
        4,2,2   YYYYMMDD (date)
        2,2,2   DDMMSS   (latitude)
        2,2,2   DDMMSS   (longitude)
        6,6,6   FF.FFF   (temp, deg. C; humidity, %; pressure, kPa)
    The result is a tuples of tuples,
 where each tuple is of the form:
    ((YY, MM, DD), (DD, MM, SS), (DD, MM, SS), (Temp, Hum, Press))'''
    fields = (((4, int), (2, int), (2, int)),       # date
              ((2, int), (2, int), (2, int)),       # latitude
              ((2, int), (2, int), (2, int)),       # longitude
              ((6, float), (6, float), (6, float))) # data
    result = []
    for line in r:
        start = 0
        for grp in fields:
            record = []
            for (width, target_type) in grp:
                text = line[start:start+width]
                field = target_type(text)
                record.append(field)
                start += width
            result.append(tuple(record))
    return result

if __name__ == '__main__':
    f = open('ex08_2_data.txt', 'r')
    ret = read_weather_data(f)
    print ret

3

# -*- encoding: sjis -*-
''' fieldが固定幅の場合、先頭からの位置の場合のどちらにも対応'''

def read_weather_data(r, fields):
    result = []

    for line in r:
        start = 0
        a_line = []
        for (width, target_type) in fields:
            text = line[start:start+width]
            field = target_type(text)
            a_line.append(field)
            start += width
        result.append(tuple(a_line))
    return result

def transform_fields(fields, last_idx):
    res = []

    for i in range(len(fields)):
        if i != len(fields)-1:
            width = fields[i+1][0] - fields[i][0]
        else:
            width = last_idx - fields[i][0]
        res.append((width, fields[i][1]))
    return(tuple(res))

def wrapper_function(data, fields):
    ''' 先頭の幅に関する値で入力のfieldの種類がどちらか判別する。
        0ならば、いったんfieldsを変換してread_weather_dataに入れる。
        これによりread_weather_dataの引数は1つ増えることになる。
    '''
    if fields[0][0] == 0:
        # 38はハードコードだが、幅の値は仕様であり、既知とする。
        fields = transform_fields(fields, 38)
    ret = read_weather_data(data, fields)
    return ret

if __name__ == '__main__':
    f = open('ex08_2_data.txt', 'r')
    '''
    fields = ((4, int), (2, int), (2, int),       # date
              (2, int), (2, int), (2, int),       # latitude
              (2, int), (2, int), (2, int),       # longitude
              (6, float), (6, float), (6, float)) # data
    '''
    fields = ((0, int),    (4, int),    (6, int),    # date
              (8, int),    (10, int),   (12, int),   # latitude
              (14, int),   (16, int),   (18, int),   # longitude
              (20, float), (26, float), (32, float)) # data
    ret = wrapper_function(f, fields)
    print ret

4,5(2問同時解答)

continueを利用することにより、インデントの数が減るので目を動かす量が減り、読みやすさは向上するものと思われる。

# -*- encoding: sjis -*-
import sys
import tsdl

def smallest_value(r):
    line = tsdl.skip_reader(r).strip()
    if not line:
        return -1 # something error occurred.
    smallest = int(line)

    for line in r:
        line = line.strip()
        if line == '-':
            continue
        value = int(line)
        if value < smallest:
            smallest = value

    return smallest

if __name__ == '__main__':
    input_file = open(sys.argv[1], 'r')
    print smallest_value(input_file)
    input_file.close()

6

以下のコードに登場するmultimol3.pdbは、通常のpdbに対し、CMNTで始まるコメント行やタブやスペースのみからなる空白の行が含まれたファイルになります。訳者のコードでは動かし方が分かりにくいので、メソッド名は採用しておりますが、1から書き直しています。

# -*- encoding: sjis -*-

def read_all_molecules(r):
    result = []
    reading = True
    while reading:
        molecule = read_molecule(r) # COMPNDという行からENDという行まで読む
        if molecule:
            result.append(molecule)
        else:
            reading = False
    return result

def get_line(r):
    ''' 空白やコメントでない行を返す。rは返す行の次の行の先頭に向かう '''

    while True:
        line = r.readline() # とりあえず1行読んで
        if not line: # 最後に来たら終了
            break
        line = line.strip() # 前後の空白を取り除いて
        if not line: # 空白ならばタブやスペースのみからなる行なので処理を続行
            continue
        elif line.startswith('CMNT'): # コメントであっても続行
            continue
        else: # それ以外はPDBファイルに必要な行である
            return line
    return ''

def read_molecule(r):
    line = get_line(r)
    if not line:
        return None

    key, name = line.split()
    molecule = [name]
    reading = True

    while reading:
        line = get_line(r)
        if line.startswith('END'):
            reading = False
        else:
            key, num, typ, x, y, z = line.split()
            molecule.append((typ, x, y, z))
    return molecule

if __name__ == '__main__':
    f = open('multimol3.pdb', 'r')
    ret = read_all_molecules(f)
    f.close()
    print ret

7

本来であれば、原子のシリアルナンバーが1ずつ大きくなっていない場合、プログラムの実行者に対し、何も結果を返さず、エラーを明示的に出してやるのがよい。途中まで出してそれを表示するということも考えられるが、正常終了に見えてしまうため、問題があるということを隠してしまうことになるので、そのような処理にしないほうがよいものと思われる。ただし、以下のコードではエラーの出し方が本テキスト読書中時点でははっきりしない(例外を投げてしまうのが一番よさげなのだが、例外の利用方法を知らない)ため、print文でエラーメッセージを出しつつ、途中で処理を打ち切るようにしている。この場合、途中までの結果が返されることになる。改めて解答しなおすことになりそうですが、ひとまず載せることにします。

# -*- encoding: sjis -*-

def read_all_molecules(r):
    result = []
    reading = True
    while reading:
        molecule = read_molecule(r) # COMPNDという行からENDという行まで読む
        if molecule:
            result.append(molecule)
        else:
            reading = False
    return result

def get_line(r):
    while True:
        line = r.readline()
        if not line:
            break
        line = line.strip()
        if not line: # 空白ならば続行
            continue
        elif line.startswith('CMNT'):
            continue
        else:
            return line
    return ''

def read_molecule(r):
    line = get_line(r)
    if not line:
        return None

    print line
    key, name = line.split()
    molecule = [name]
    reading = True
    check_num = 1
    ret_mol = True

    print "line = ", line
    while reading:
        line = get_line(r)
        if line.startswith('END'):
            reading = False
        else:
            print "!", line
            key, num, typ, x, y, z = line.split()
            if int(num) != check_num:
                print "serial number error in %s!" % molecule[0]
                return None # Noneとすることで続きの処理が行われなくなる
            check_num += 1
            molecule.append((typ, x, y, z))
    return molecule

if __name__ == '__main__':
    f = open('multimol4.pdb', 'r') # ファイルは適当にいじっておくように。
    ret = read_all_molecules(f)
    f.close()
    print ret

2012年5月25日金曜日

TopCoder SRM392 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

2007年の1月にお菓子屋さんが飴を製造した。毎月の最後の日に、お母さんは子供にいくつか飴を食べることを許している。飴の寿命は1/1から飴が食べられるまでの日数である。例えば、1/31に食べられた飴の寿命は31日、12/31に食べられた飴の寿命は365日である(うるう年でないことに注意!)。eatenCandies[]という2007年の各月の最後に食べられた飴の数が与えられたとき(配列の添字0は1月、添字1は2月を表す。以下同様)、飴の平均寿命を計算して返すメソッドを作成せよ。

私の解答はこちら。

public class AverageCandyLifetime {

 public double getAverage(int[] eatenCandies) {
  int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 各月の日数
  int sum = 0;
  int lifetimes = 0;
  int nCandies = 0;
  for( int i=0 ; i<eatenCandies.length ; i++ ){
   lifetimes += days[i];
   nCandies += eatenCandies[i];
   sum += eatenCandies[i] * lifetimes;
  }
  return (double)sum/nCandies;
 }

}

得点は244.91/250、1回のsubmitでシステムテストクリア。中央値は約215点。

2012年5月23日水曜日

TopCoder SRM391 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

中国北部では豪雪で苦労している。豪雪により、中国の南北を結ぶ重要な高速道路が閉鎖された。あなたは豪雪に覆われた高速道路の地域の始点と終点についていくつかの報告を受けた。始点と終点が整数型の配列として与えられたとき、雪で覆われた道路の距離の合計を返すメソッドを作成せよ。なお、報告では領域が重複していることもあることに注意せよ。

私の解答はこちら。

public class SnowyWinter {

 public int snowyHighwayLength(int[] startPoints, int[] endPoints) {
  int size = 10000;
  boolean[] isCoveredSnow = new boolean[size]; // trueの数が雪で覆われた道路の距離になる
  for( int i=0 ; i<startPoints.length ; i++ ){
   for( int j=startPoints[i] ; j < endPoints[i] ; j++ ){
    isCoveredSnow[j] = true; // 雪で覆われている領域とする
   }
  }
  int len = 0;
  for( int i=0 ; i<size ; i++ ){
   if( isCoveredSnow[i] ) len++;
  }
  return len;
 }

}

得点は244.48/250、1回のsubmitでシステムテストクリア。条件で与えられているサイズの上限を与えずに解けると文句なしなのですがね。

2012年5月22日火曜日

初めてのコンピュータサイエンス第7章解答

第7章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。全部あわせるとかなり長い解答です。問題文は載せませんので悪しからず。本は必要なら買いましょう。間違い(コード、英語)は指摘していただければ。よほどひどい解答が見つかったなら対応いたします。その前にこの章の個人的なメモ。

  • enumerateというシーケンスを受け取ると添え字とセットにして返す関数がある
  • x, y = 1, 2のような多重代入という仕組みがある。右辺は[1, 2]のようなリスト、文字列などシーケンスでも動作する。
  • ネストされたリストの長さが一定でない場合、ラグリスト(不規則リスト)と呼ばれる

1

問題文中の「前の値の2倍」というのは引数にとったリストの各要素を2倍しろという意味にとりました。もしかすると、1だけ小さい添え字のことを指しているのかもしれません。曖昧な問題文なのですが、一応解答をあげておきます。英語ではpreceeding valueを2倍なので、1つ前の添え字というよりも、処理前の要素と思うのですが...

def double_preceeding_correct(values):
    if values == []:
        pass
    else:
        values[0] = 0
        for i in range(1, len(values)):
            values[i] *= 2
    return values

print double_preceeding_correct([1, 2, 3])

2

rat1 = [23, 24, 22, 21, 22, 25, 26, 26, 23, 22]
rat2 = [21, 23, 24, 25, 26, 24, 24, 22, 21, 24]
# a)の解答
msg = "Rat %d weighed more than Rat %d on Day %d."
if rat1[0] > rat2[0]:
    print msg % (1, 2, 1) # 後から数値のみを付け加えることもできる
elif rat1[0] < rat2[0]:
    print msg % (2, 1, 1)
# b)の解答
if rat1[0] > rat2[0] and rat1[len(rat1)-1] > rat2[len(rat2)-1]:
    print "Rat 1 remained heavier than Rat 2."
else:
    print "Rat 2 became heavier than Rat 1."
# c)の解答
if rat1[0] > rat2[0]:
    if rat1[len(rat1)-1] > rat2[len(rat2)-1]:
        print "Rat 1 remained heavier than Rat 2."
    else:
        print "Rat 2 became heavier than Rat 1."

3~5

いずれも簡単な処理なので、一度にまとめて解答する。

print range(33, 50) # 3の解答

print range(10, 0, -1) # 4の解答、リストを降順にするには第3引数のステップ幅に負数を指定する

# 5の解答
total = 0
for num in range(2, 23):
    total += num

print float(total) / len(range(2,23)) # 整数/整数なので、切捨を避けるためfloatに変換しておく

6

もう少しコードを変形しすぎずに解答したいところなのですが...

def remove_neg_correct(num_list):
    '''num_listから正しく負数を取り除く'''
    result = []
    for item in num_list:
        if item >= 0:
            result.append(item)
    return result

aList = [1, 2, 3, -3, 6, -1, -3, 1]
result = remove_neg_correct(aList)
print result

7~8

def print_triangle_right(num):
    ''' Tを右三角形にして表示する'''
    for i in range(1, num+1):
        print 'T' * i

print_triangle_right(7)

def print_triangle_left(num):
    ''' Tを左三角形にして表示する'''
    for i in range(1, num+1):
        print ' ' * (num-i) + 'T' * i

print_triangle_left(7)

9

def print_triangle_right_while(num):
    ''' Tを右三角形にして表示する'''
    i = 1
    while i < num + 1:
        print 'T' * i
        i += 1

print_triangle_right_while(7)

def print_triangle_left_while(num):
    ''' Tを左三角形にして表示する'''
    i = 1
    while i < num + 1:
        print ' ' * (num -i) + 'T' * i
        i += 1

print_triangle_left_while(7)

10

rat_1_weight = 10
rat_2_weight = 10
rat_1_rate = 0.04
rat_2_rate = 0.04

# a)の解答
nWeek = 0
current_weight =  rat_1_weight
while True:
    nWeek += 1
    current_weight *= (rat_1_rate + 1)
    if current_weight > rat_1_weight * 1.25:
        break

print nWeek

# b)の解答
rat_2_rate = rat_1_rate + 0.03
rat1_current_weight = rat_1_weight
rat2_current_weight = rat_2_weight
nWeek = 0
while True:
    rat1_current_weight *= (rat_1_rate + 1.0)
    rat2_current_weight *= (rat_2_rate + 1.0)
    nWeek += 1
    if rat2_current_weight / rat1_current_weight > 1.1:
        break

print nWeek

11

import media

# 同じフォルダにあるマドレーヌの画像を利用している
madeleine = media.load_picture('pic207.jpg')
width, height = \
    media.get_width(madeleine), media.get_height(madeleine)

rotate = media.create_picture(height, width)
for y in range(0, height):
    for x in range(0, width):
        p_from = media.get_pixel(madeleine, x, y)
        p_to = media.get_pixel(rotate, height-y-1, x)
        media.set_color(p_to, media.get_color(p_from))

media.show(rotate)

12

a)の解答

import media

def swap_pix(pic, x1, y1, x2, y2):
    ''' swap color between (x1, y1) and (x2, y2) '''
    p1 = media.get_pixel(pic, x1, y1)
    p2 = media.get_pixel(pic, x2, y2)
    c1 = media.get_color(p1)
    c2 = media.get_color(p2)
    media.set_color(p1, c2)
    media.set_color(p2, c1)

def return_pic_size(pic):
    return media.get_width(pic), media.get_height(pic)

madeleine = media.load_picture('pic207.jpg')
width , height = return_pic_size(madeleine)

for y in range(0, height):
    for x in range(0, width/2):
        swap_pix(madeleine, x, y, width-x-1, y)

media.show(madeleine)

b)の解答。a)から改良を加えています。関数作成にこだわってみました。

import media

def swap_pix(pic, x1, y1, x2, y2):
    ''' swap color between (x1, y1) and (x2, y2) '''
    p1 = media.get_pixel(pic, x1, y1)
    p2 = media.get_pixel(pic, x2, y2)
    c1 = media.get_color(p1)
    c2 = media.get_color(p2)
    media.set_color(p1, c2)
    media.set_color(p2, c1)

def return_pic_size(pic):
    return media.get_width(pic), media.get_height(pic)

def y_axial_symmetry(pic):
    width , height = return_pic_size(madeleine)
    for y in range(0, height):
        for x in range(0, width/2):
            swap_pix(madeleine, x, y, width-x-1, y)

def x_axial_symmetry(pic):
    width , height = return_pic_size(madeleine)
    for y in range(0, height/2):
        for x in range(0, width):
            swap_pix(madeleine, x, y, x, height-y-1)

if __name__ == '__main__':
    madeleine = media.load_picture('pic207.jpg')
    x_axial_symmetry(madeleine)
    # y_axial_symmetry(madeleine)
    media.show(madeleine)

13

picを左上を基準にユークリッド距離でnピクセル離れた位置にある画素のみをサンプリングします。縮小した画像のサイズ計算が面倒ですね。

import math
import media

def down_scaling(pic, n):
    width, height = media.get_width(pic), media.get_height(pic)
    new_pic = media.create_picture(int(math.ceil(float(width)/n)),
                                   int(math.ceil(float(height)/n)))
    print new_pic.get_height(), new_pic.get_width()
    for y in range(height):
        for x in range(width):
            if y % n != 0 or x % n != 0:
                continue
            # print x, y, x/n, y/n
            p_from = media.get_pixel(pic, x, y)
            p_to = media.get_pixel(new_pic, x / n , y / n )
            target_col = media.get_color(p_from)
            media.set_color(p_to, target_col)

    return new_pic

if __name__ == '__main__':
    f = media.load_picture('pic207.jpg')
    ret = down_scaling(f, 2)
    media.show(ret)

14

問題よりも親切に10*10以外の平均値フィルタも実装しておりますが、端の処理だけは完全ではありません。問題の前提として、画像サイズは平均値フィルタの1辺のサイズで割り切れることを仮定しているため、これで解答としては十分と考えております。

import media

def fill_color(pic, x, y, n = 10):
    ''' make (x, y) to (x + n, y + n) rectangle pixels
        to the same color '''
    # print x, y
    r = g = b = 0
    for height in range(n):
        for width in range(n):
            a_pic = media.get_pixel(pic, x + width, y + height)
            r += media.get_red(a_pic)
            g += media.get_green(a_pic)
            b += media.get_blue(a_pic)
    r /= n*n
    g /= n*n
    b /= n*n
    set_color = media.create_color(r, g, b)
    for height in range(n):
        for width in range(n):
            a_pic = media.get_pixel(pic, x + width, y + height)
            media.set_color(a_pic, set_color)
    return pic

def mosaic_filter(pic, n = 10):
    ''' warning : edge is not processed if width and height is
        not divisible by n.
    '''
    width, height = media.get_width(pic), media.get_height(pic)
    for y in range(int(height/n)):
        for x in range(int(width/n)):
            fill_color(pic, x*n, y*n, n)
    return pic

if __name__ == '__main__':
    f = media.load_picture('pic207.jpg')
    mosaic_filter(f, 10)
    media.show(f)

15

ループをネストさせてモノクロイメージを作成する関数を作れという指示に従わない書き方もあるのですが、ここでは省略。create_monochrome_image関数の第2引数は3要素が必要で、それぞれr, g, bの重み付けに対応しています。全部同じ値にすればa)の解答、緑の重みを上げたのはb)の解答になります。重みはrgbからモノクロに変換する際によく使われる値を利用しています。実際のところ2種類でどの程度違うのかといわれると、私の目ではよく分からないところではありますが...

import media

def create_monochrome_image(pic, weight):
    ''' pic is picture to be processed.
        weight is weight for r, g, b values when we
        create monochrome image from color image.
        Default value should be [a, a, a], but
        green has more effective than other colors for human eyes,
        so when we take this fact into considaration,
        please change weight. ex.[a, 2a, a] (weight of green is hevier than that of others)
    '''
    s = float(sum(weight))
    for i in range(len(weight)):
        weight[i] /= s

    width, height = media.get_width(pic), media.get_height(pic)
    for y in range(height):
        for x in range(width):
            a_pic = media.get_pixel(pic, x, y)
            r = media.get_red(a_pic)
            g = media.get_green(a_pic)
            b = media.get_blue(a_pic)
            val = round(r * weight[0] + g * weight[1] + b * weight[2])
            col = media.create_color(val, val, val)
            media.set_color(a_pic, col)
    return pic

if __name__ == '__main__':
    f = media.load_picture('pic207.jpg')
    # create_monochrome_image(f, [1, 1, 1])
    create_monochrome_image(f, [0.299, 0.587, 0.114])
    media.show(f)

2012年5月20日日曜日

TopCoder SRM390 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

あなたの幼い息子が左手で数を数えている。親指から小指へ向かって順に数えていく。小指まで数えたら親指へ向かって逆方向に数えていく。これを目的の数を数える前で行う。途中で数える指を飛ばしたりはしないものとする。例えば、10まで数えるとしたら、息子さんは親指、人差し指、中指、薬指、小指、薬指、中指、人差し指、親指、人差し指の順で数える。悲しいことに、息子さんの指の1本はケガをしており、その指については限られた回数しか数えることができない。指には1~5までそれぞれ親指から小指に割り当てられている。weakFingerというケガをしている指を表す数字と、maxCountというケガをしている指を数えられる回数の上限が与えられたとき、数え続けることのできる回数の最大値を求めよ。もし数えはじめることができないときは0を返すようにせよ。

私の解答はこちら。

public class FingerCounting {

 public int maxNumber(int weakFinger, int maxCount) {
  int nCount = 0; // ケガをしている指を数えた回数
  int ret = 0; // 指を数えた回数の合計
  int numFinger = 0; // 現在注目している指の番号
  boolean countUp = true; // 親指から小指に向かって数えているときにtrue
  while( true ){
   if( numFinger == 5 ){ // 小指まで数えたら逆走
    countUp = false;
   }else if( numFinger == 1){ // 親指から小指へ向かって数える
    countUp = true;
   }
   numFinger = countUp ? numFinger+1 : numFinger-1; // 次の指へ進める
   if( numFinger == weakFinger ){ // もしケガをしている指なら
    if( nCount == maxCount ) break; // 数えられる回数の上限なら終了
    nCount++; // そうでなければケガした指のカウントした回数を1増やす
   }
   ret++;
  }
  return ret;
 }

}

得点は225.38/250、1回のsubmitでシステムテストクリア。中央値は約170点。printしながら確認していたら、maxCountが大きいときに時間的に間に合わなくなったので、結構ギリギリです。上の問題はO(n)のアルゴリズムで解いてますが、うまくやればO(1)で答えが出そうな気もします。

2012年5月18日金曜日

TopCoder SRM389 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

あなたは積みあがった本を、各箱の重量制限にひっかからないようにしつつ、できるだけ1つの箱に本を詰めようとしている。できるだけ本を詰め込んだら、箱を閉じて封をして、次の箱に本を詰めはじめる。本は積み上げたものの上から順に取り、次の本をとる前に箱に詰める。本の重量はweights[]という整数型の配列で与えられており、最初の要素は積み上げた本の1番上の重量を表し、最後の要素は積み上げた本の一番下の本の重量を表している。箱に詰められる重さの上限はmaxWeightという変数で与える。このとき、すべての本を詰めるのに必要となる箱の数の最小値を返すメソッドを作成せよ。

私の解答はこちら。

public class BoxesOfBooks {

 public int boxes(int[] weights, int maxWeight) {
  int current = 0;
  int nBox = 1;
  if( weights.length == 0 ) return 0;
  for( int i=0 ; i<weights.length ; i++ ){
   if( current + weights[i] > maxWeight ){ // もし次の本を詰めると重さの上限を超えるなら
    current = weights[i]; // 次の箱にその本を詰め、
    nBox++; // 必要となる箱の数を1増やす
   }else{
    // 次の本を詰めても重さの上限を超えない場合は、現在の箱に入っている本の重さの合計を増やす
    current += weights[i];
   }
  }
  return nBox;
 }

}

得点は243.02/250、1回のsubmitでシステムテストクリア。中央値は約217点。

2012年5月17日木曜日

英単語学習記録20120517

英単語 意味
commit(罪などを)犯す
participate in ~~に参加する(前置詞に注意)
as to ~~に関して
stay up寝ずに起きている
think nothing of ~~を何とも思わない
sign up登録する
abruptry急に
captivity閉じ込めること、とらわれ
outweigh上回る
frown顔をしかめる
go throught with ~~を終わらせる
be particular about ~~の好みにうるさい
not at all少しも~ない、どういたしまして
reunion同窓会
dimほの暗い、(ものの形が)よく見えない
timid内気な、臆病な
signature署名、サイン
with ease容易く
know better than to ~~するほど愚かではない
saliva唾液
cavity虫歯、空洞
intuitive直感的な
lingua franca(イタリア語で)共通語
as of ~~時点で
leverage行動力、影響力、てこ、活用する
mature成熟した、十分に成長した
novel新手の、小説
forthcoming間近に迫った
bulk体積、大部分、巨大、巨漢、食物繊維

初めてのコンピュータサイエンス第6章解答

第6章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。

  • 0、0.0はFalseであるが、それ以外の値はTrue

1

>>> True and not False
True
>>> True or True and False
True
>>> not True or not False
True
>>> True and not 0
True
>>> 52 < 52.3
True
>>> 1 + 52 < 52.3
False
>>> 4 != 4.0
False

2

後半のルールはよくない。被演算子のうち、0やFalseになるものを返すべきである。例えばx = 3 and 0はFalseだが、3を返すのはTrueを意味することになるので矛盾する。

3

>>> z = x and y # a)の解答
>>> z = not x # b)の解答
>>> z = x or y # c)の解答

4

>>> result = full or empty

5

友人の発言は正しい。二つの論理値がTrueとFalseという異なった値になっているときにifの中がTrueになるようにできているからである。

6

>>> x = -1
>>> result = x == abs(x)
>>> result
False

7

def different(a, b):
    return a != b

8

population = 10000
land_area = 200
if population > 10000000:
    print population

if 10000000 >= population >= 35000000:
    print population

if population / land_area > 100:
    print "過密"

if population / land_area > 100:
    print "過密"
else:
    print "過疎"

9

wikipediaで温度変換の公式を参照せよということなのですが、多少変更が加えられたのか、Newtonなどの温度へ変換する公式が指定されたページ内に見つからないため、全部実装するのは断念しています。考え方のみ参考にしてください。b)の解答は新しい単位を追加すると、if文を2回追加することになります。これはsourceをセルシウス度に変換するときに1度、セルシウス度からtargetに変更するのに1度追加する必要があるためです。

def temperatures(t, source, target):
    ''' Kelvin, Celsius, Fahrenheit, Rankine, Delisle, Newton, Reaumur
        とあるのだが、wikipediaでは最初の4つしかないので、4つのみで実装する
    '''
    if source == 'Kelvin':
        temp = float(t) - 273.15
        pass
    elif source == 'Celsius':
        temp = float(t)
        pass
    elif source == 'Fahrenheit':
        temp = (t - 32) * 5.0 / 9
        pass
    elif source == 'Rankine':
        temp = (t - 491.67) * 5.0 / 9
        pass
    else:
        return 'Error in source'

    if target == 'Kelvin':
        return temp + 273.15
    elif target == 'Celsius':
        return temp
    elif target == 'Fahrenheit':
        return temp * 9.0 / 5 + 32
    elif target == 'Rankine':
        return (temp + 273.15) * 9.0 / 5
    else:
        return 'Error in target'

print temperatures(10, 'Celsius', 'Celsius')
print temperatures(10, 'Celsius', 'Kelvin')

10

先に3.0未満か評価した。もしくは最初のifで3.0以上7.0未満で「酸性」と表示するような変更をしてもよいでしょう。

ph = 2.5
if ph < 3.0:
    print "%sは強酸性です。注意してください。" % ph
elif ph < 7.0:
    print "%sは酸性です。" % ph

11

a)、b)はどちらも"酸性です!"と表示される。c)の解答は以下の通り。

ph = float(raw_input("ph値を入力してください"))
if ph < 7.0:
    print "酸性です!"
if ph < 4.0: # elifからifに書き換える
    print "強酸性です!"

12

以下のようにすれば同じように書き換えればよい。

age = 30
bmi = 19.2
table = [['高', '中'], # 中、高を入れ替えておく
         ['中', '低']] # 低、中も同様
young = age < 45
light = bmi < 22.0 # heavy = bmi >= 22.0からの書き換え 
risk = table[young][light]
print risk

TopCoder SRM388 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

厳密に増加する数列とは、前の数よりも大きい数字が続く数列である。厳密に減少する数列とは直前の数よりも小さい数字が続く数列である。厳密に単調な数列は厳密に増加する、もしくは厳密に減少するような数列を指す。例えば1, 5, 6, 10は厳密に増加する数列であり、1, 2, 2, 3は厳密に単調な数列ではない。seq[]という整数型の配列が与えられたとき、その部分列が厳密に単調になるもののうち、 最長になるものを求め、その長さを返すようなメソッドを作成せよ。

私の解答はこちら。

public class MonotoneSequence {

 public int longestMonotoneSequence(int[] seq) {
  int maxlen = 0; // 厳密に単調な数列の最大長
  int len = 0; // 現在見ている数列で連続に厳密に単調な数列が続いている長さ
  int prev = -1; // 直前の値
  // 厳密に増加する数列の中で最大の長さを計算
  for( int i=0 ; i<seq.length ; i++ ){
   if( seq[i] > prev ){
    len++;
    maxlen = Math.max(maxlen, len);
   }else{
    len = 1;
   }
   prev = seq[i];
  }
  System.out.println(maxlen);
  len = 0;
  prev = Integer.MAX_VALUE;
  // 厳密に減少する数列の中で最大の長さを計算
  for( int i=0 ; i<seq.length ; i++ ){
   if( seq[i] < prev ){
    len++;
    maxlen = Math.max(maxlen, len);
   }else{
    len = 1;
   }
   prev = seq[i];
  }
  return maxlen;
 }

}

得点は237.07/250、1回のsubmitでシステムテストクリア。中央値は約189点。

2012年5月16日水曜日

TopCoder SRM387 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

A[]という整数型の配列が与えられる。Aは等差数列か等比数列のどちらかである。Aがどちらであるかを判定し、Aの最後の要素に続く要素を返すメソッドを作成せよ。なお、Aはどちらかであるか判別可能であり、解答は32bit型の符号付き整数の範囲に収まることが保証されている。

私の解答はこちら。

public class GuessingNextElement {

 public int guess(int[] A) {
  if( A[1] - A[0] == A[2] - A[1] ){ // 問題文ではAが3つ以上の要素を持つことを保証している
   return A[A.length-1] + (A[1] - A[0]); // Aが等差数列である場合
  }else{
   int ratio = A[1] / A[0]; // Aが等比数列である場合
   return A[A.length-1] * ratio;
  }
 }

}

得点は207.77/250、2回目のsubmitでシステムテストクリア。if文の中身を割り算でやると割り切れないケースで失敗するので、等差数列かそうでないかで判定する方が間違いが出にくいですね。1回目の提出はシステムテストで見事に弾かれました。中央値は約230点。

2012年5月15日火曜日

TopCoder SRM386 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

あなたは棚に一列に並んだトロフィーを所有している。トロフィーの高さはtrophies[]とうい整数型の配列で与えられており、棚の左から右に順番に高さの値が入っている。棚は人が入るときに直接左から見える位置にある。別の言い方をすれば、一番左のトロフィーは完全に見えるし、隣のトロフィーはトロフィーの並ぶ直線の後ろにあるように見える。不幸なことに、背の高いトロフィーが左側にあると他の奥にあるトロフィーが見えるのを遮ってしまう。トロフィーはその手間にあるトロフィーがそれよりも背が低い場合にのみ見えるものとする。そしてあなたは、棚を180度回転させたなら見えるトロフィーが増えるのではないかと考えた。さて、最初の要素が左から見たときに見えるトロフィーの数、2番目の要素は右から見たとき(注:要は180度棚を回転させたときを考えているのでしょう)に見えるトロフィーの数からなる配列を返すメソッドを作成せよ。

私の解答はこちら。

public class TrophyShelf {

 public int[] countVisible(int[] trophies) {
  int min = -1;
  int[] nVisible = new int[2];
  for( int i=0 ; i<trophies.length ; i++ ){ // 左から見た場合
   if( trophies[i] > min ){
    nVisible[0]++;
    min = trophies[i];
   }
  }
  min = -1;
  for( int i=trophies.length-1 ; i>=0 ; i-- ){ // 右から見た場合
   if( trophies[i] > min ){
    nVisible[1]++;
    min = trophies[i];
   }
  }
  return nVisible;
 }

}

得点は245.06/250、1回のsubmitでシステムテストクリア。左右のどちらから見る場合も基本的なロジックは同じで、問題としては簡単とは思います。

2012年5月14日月曜日

初めてのコンピュータサイエンス第5章解答

第5章の解答を上げます。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。

  • リストはミュータブル(書き換え可能)であるのに対し、数値や文字列はイミュータブル(書き換えできない)である。
  • リストではエイリアシングによるエラーに注意。エイリアシングとは違う変数名が同じオブジェクトを指すことである。数値や文字列オブジェクトではエイリアシングはない。
  • リストメソッドは新しいリストを生成しない。また、popメソッドを除き、リストに関連するメソッドの返り値はNoneになる。
  • 1個の要素を持つタプル(イミュータブルなシーケンス)は(data, )のように","をつける必要がある。

1~4

>>> alkaline_earth_metals = [4, 12, 20, 38, 56, 88] # 1の解答
>>> alkaline_earth_metals[5] # 2の解答
88
>>> alkaline_earth_metals[-1]
88
>>> len(alkaline_earth_metals) # 3の解答
6
>>> max(alkaline_earth_metals) # 4の解答
88

5

改行かスペースかという違いがある。すなわちprint aは改行せず、print a,はスペースを入れる。

6

問題文には「5.5 スライシング」のhalf_livesリストとあるが、正しくは「5.3 リストの組み込み関数」と思われる。

>>> half_lives = [87.74, 24110.0, 6537.0, 14.4, 376000.0]
>>> for val in half_lives:
...     print val
... 
87.74
24110.0
6537.0
14.4
376000.0

7

>>> for val in half_lives:
...     print val, # ,を入れることで空白区切りで、改行なく出力する
... 
87.74 24110.0 6537.0 14.4 376000.0

8

country_populations = [1295, 23, 7, 3, 47, 21]
total = 0
for cp in country_populations:
    total += cp

print total

9~13

temps = [25.2, 16.8, 31.4, 23.9, 28, 22.5, 19.6] # 9の解答
temps.sort() # 10の解答
# 11の解答
cool_temps = [t for t in temps if t < 20] # リスト内包表記を用いている
# cool_temps = temps[:2]とする方法もあるが、一般化した解答を採用した
print cool_temps # tempsはソート済みなので、昇順に表示される
warm_temps = [t for t in temps if t >= 20]
print warm_temps # 上と同じくソート済みで表示される
temps_in_celsius = cool_temps + warm_temps # 12の解答
temps_in_fahrenheit = [] # 以下13の解答
for cels in temps_in_celsius:
    fahr = cels * 1.8 + 32
    temps_in_fahrenheit.append(fahr)

14~16

# 14の解答
alkaline_earth_metals = [[4, 9.012], [12, 24.305], [20, 40.078], \
 [38, 87.62], [56, 137.327], [88, 226]]
print alkaline_earth_metals
# 15の解答
for elem in alkaline_earth_metals:
    print elem[0], elem[1]
# 16の解答
number_and_weight = []
for elem in alkaline_earth_metals:
    number_and_weight.append(elem[0])
    number_and_weight.append(elem[1])
print number_and_weight

17

f = open('alkaline_metals.txt', 'r')
number_and_weight = []
for line in f:
    elems = line.split()
    number_and_weight.append([elems[0], elems[1]])

print number_and_weight

18

valuesに[0, 1, 2]という値が設定された後、values[1] = valuesによって、1という要素が[0, 1, 2]に差し替えられる。リストはミュータブルなので、値が書き換えられ、結局[0, [0, 1,2], 2]というリストになる。

19

def mystery_function(values):
    ''' 各リストのn番目の要素をn番目のリストの要素にする
        リストの要素数が不変でn*mの長方形型であれば、
        転置に相当する操作が行われる
    '''
    result = []
    for i in range(len(values[0])):
        result.append([values[0][i]]) # 先頭は一列目の値
        for j in range(1, len(values)):
            # result[-1]は上でappendしたもの。
            # i列目のj番目の要素を順にリストに追加する
            result[-1].append(values[j][i])
    return result

20

ミュータブルな文字列あったとき、例えば途中の文字を大文字に変換するといった操作は、便利であろう。イミュータブルにしている理由としては、文字列の生成時にメモリの割り当てを固定できるという点である。これによりパフォーマンスの向上が期待できる(www.python.jpのオフィシャルサイトにそのような記述がある)。

21

ソートするとNoneが返される。文字列と数字を比較すること自体に意味はない(Javaなどのchar型と比較するのは意味があるといえなくも無いですが...)。例えば3章の文字列の規則と照らし合わせ、'123' - 4は何かと問われると、定義する方法がないことに気づかされる('123'+(-4)の'+'は文字列として結合するか、足し算とみなすかで曖昧さが発生してしまう。Python側で勝手な処理をするとエラーの捕捉が難しくなってしまう)。返り値がNoneであればエラー処理をせよという考え方もできるので、Pythonの動作としては、このままでもよいものと思われる。

>>> ret = [1, 'a', 2, 'b'].sort()
>>> print ret
None

TopCoder SRM385 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

ロシア人は制限速度を守らないという噂がある。というのも、ロシアでは暗黙的に速度制限がかけられていることがあるためである。 より具体的には、市街の速度制限は60km/hであるのだが、そのようなことを運転者に思い出させるような標識はない。同様に、市街の速度制限は90km/hである。 速度制限は30や95といった標識によって明示的に特定できる。道路標識には、「標準的な速度制限領域」という標識がある。これは、その場所における標準的な速度制限になるということを意味している。標識は運転手に速度制限を思い出されることに用いられ、連続的にそのような標識をみかけることもある。 要は、速度制限が変わる次のような標識に注意する必要がある。

  • X(数字) - 速度制限がX km/hということを明示している
  • 標準的な速度制限に戻ることを示す標識 - 市街なら60、市外なら90
  • 市街と市外を分ける境界 - 速度制限がそこを境に変わるということ

signsという標識を表す文字列が与えられたとき、現在の速度制限が何km/hになっているかを返すメソッドを作成せよ。signs[]の中身は"50"のように数字が中身に入る場合、"default"という、その場所における標準速度制限に戻す場合、"city"という領域の境界(市街から市外、市外から市街のどちらも含む)である場合の3つがある。あなたは市街の中から運転を始め、特別な速度制限のある市外へと出ることになるものとする。

私の解答はこちら。

public class RussianSpeedLimits {

 public int getCurrentLimit(String[] signs) {
  int ret = 0;
  boolean inCity = true; // 現在市街にいればtrue、市外ならfalse
  for( int i=0 ; i<signs.length ; i++ ){
   if( signs[i].equals("default") ){
    ret = inCity ? 60 : 90; // その場所における初期状態に戻す
   }else if( signs[i].equals("city") ){
    inCity = inCity ? false : true; // 位置情報を変えて
    ret = inCity ? 60 : 90; // 速度の上限を変更する
   }else{
    ret = Integer.parseInt(signs[i]); // 数値が含まれている場合
   }
  }
  return ret;
 }

}

得点は231.05/250、1回のsubmitでシステムテストクリア。中央値は約201点。

2012年5月13日日曜日

初めてのコンピュータサイエンス第4章解答

第4章の解答を上げます。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。

  • import文は実行も同時に行っている。つまり、importするライブラリにprint関数があると、それが実行され、何か表示されるということになる。
  • builtin変数の__main__は重要。これにより実行しているファイルがimportする側なのか、importされた側なのか判別できる
  • python2.7でmediaモジュールを動かすときはこちらを参考に各種モジュールをインストールする。
  • サンプルで紹介されている画像pic207.jpgはこちらにある。ただし、テキストで利用している実物とは若干違うように思われる。

1

import math

print abs(round(-4.3))
print math.ceil(math.sin(34.5))

2

# b)の解答
import calendar
year = 2013
while True:
    if calendar.isleap(year):
        print year # 2016が表示される
        break
    year += 1
# c)の解答
help(calendar.isleap)

# isleap関数を用いたd)へのアプローチ方法
def nLeap(rng):
    nleap = 0
    for i in rng:
        if calendar.isleap(i):
            nleap += 1
    return nleap

# 1行が長いコードになる場合は\で続けて入力できる
print 'The number of leap year between %d to %d = %d' % \
 (2000, 2050, nLeap(range(2000, 2051)))

# d)の解答
print calendar.leapdays(2000, 2051)

# e)の解答
# help(calendar.weekday)
# 1が返されるので火曜日になる。0が月曜日~6が日曜日という仕様である。
print calendar.weekday(2016, 7, 19)

3

>>> 'boolean'.upper() # a)の解答
'BOOLEAN'
>>> 'C20 H20'.find('2', 0) # b)の解答
1
>>> 'C20 H20'.find('2', 2) # c)の解答。添え字1に'2'があるので2から後ろを探索する
5
>>> 'Boolean'[0].isupper() # d)の解答
True
>>> 'MoNDaY'.lower().capitalize() # e)の解答、文字列処理のメソッドは次々とかませられる
'Monday'
>>> ' Monday'.strip() # f)の解答
'Monday'

4

実数ではなく、文字列として表記しようとしているから。

5

mediaモジュールは特定の用途に限られているから標準ライブラリに含んでいない。標準モジュールに組み込むか否かの基準としては、標準的なデータに関わる操作に限ったものと思われる。標準ライブラリに含まれていないものについてはググル、もしくはPyPIで探すとよいでしょう。

6

import media
f = media.choose_file()
pic = media.load_picture(f)
media.show(pic)
media.show(pic)

7

import media
f = media.choose_file()
pic = media.load_picture(f)
for p in media.get_pixels(pic):
    media.set_red(p, 0)
media.show(pic)

8

import media
f = media.choose_file()
pic = media.load_picture(f)
for p in media.get_pixels(pic):
    media.set_green(p, media.get_green(p)/2)
media.show(pic)

9

import media
f = media.choose_file()
pic = media.load_picture(f)
for p in media.get_pixels(pic):
    col = media.get_color(p)
    col.r = col.b = col.g = (col.r + col.g + col.b)/3
    # set_colorメソッドは3色をまとめたオブジェクトが必要であることに注意!
    media.set_color(p, col)

media.show(pic)

10

ValueError: Invalid red value specified.というメッセージが出てエラーになる

import media
pic = media.load_picture(media.choose_file())
for p in media.get_pixels(pic):
    new_r = media.get_red(p) * 2
    media.set_red(p, new_r)

media.show(pic)

11

メディアは変更を加えていないイメージだけ利用するという制約は必要ないものと思われる。より画像をきれいに見えるようにする処理など、事実を的確に伝えるのに必要な処置はあってしかるべきと思われる。

12

a)について。浮動小数点を含む計算において、その値がある値になっているか評価するのは、丸め誤差が含まれていることがほとんどなので、難しくなってしまう。

b)について。距離の計算結果と想定される値の差が10^-6以下であれば、テストに合格と判断している。問題点としては10^-6という値の設定理由が不明瞭であること、またx0とx1を入れ替えたケースを追加することが必要になるということである。2点間のユークリッド距離を計算するのに4つの値が現れるが、そのうち、変化する値が2種類しかないのは心もとない。

英単語学習記録20120513

英単語 意味
authority当局
craft工芸
assembly集合
drawingくじびき
prize賞品
complimentary敬意を表して、称えて、無料の
break the ice話の口火を切る
substitute~を代用する
generous気前のよい
be well off裕福である
on the go忙しくしている
lose face面目を失う
harmful有害な
make up~を構成する
pedestrian歩行者
deprive奪う
devote oneself to ~~に専念する
nerve神経
favor親切な行為、好意
dull鈍い、どんよりとした
finish off~~を仕上げる
in the long run長い目で見れば、結局は
dissolve(液体が物を)溶かす
suck吸う、吸い上げる、飲み込む
object to~~に反対する
reception受け取ること、入会
definitely明確に、きっぱりと
sue訴訟を起こす、請う
domesticate飼いならす、なじませる、教化する

2012年5月12日土曜日

TopCoder SRM384 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

ジェーンは最高の体型を維持しようとしている。ジェーンの姉はそのことを知っているので、ジェーンにいたずらをすることにした。ジェーンの古い目盛りを破棄したのちに、本当の体重に代わり体重の二乗を示す目盛りを用意した。その変化に気付かず、ジェーンはしばらくその目盛りを使い続けていた。そしてある朝、"うわっ、私apparentGainポンドも太った!"と叫んだ。apparentGainという本当の体重と以前の体重の二乗の差が与えられたとき、ジェーンの現在の体重であり得る値を、昇順にして整数型の配列として返せ。体重は1以上の整数とする。

一見問題文が分かりにくいのだが、体重は整数の値をとり得るわけで、現在の体重をcw、以前の体重がpwという整数であったときにcw*cw-pw*pw=apparentGainになるようなcwは何かということを聞いているのである。私の解答は以下の通り。

import java.util.ArrayList;
import java.util.Arrays;

public class Prank {

 public int[] realWeight(int apparentGain) {
  ArrayList<Integer> aList = new ArrayList<Integer>();
  // apparentGainが1~100000ということから、過去の体重の探索範囲が
  // およそ現在の体重-searchから現在の体重-1でよいことになる。
  // 例えば現在の体重が10000で過去の体重が100ということはあり得ない。
  long search = (long)Math.sqrt(100000)+1;
  for( long i=1 ; i<=apparentGain/2+1 ; i++ ){ // iが現在の体重
   long start = Math.max(1, i - search);
   for( long j=start ; j<=i ; j++ ){ // jは過去の体重
    if( i*i - j*j == (long)apparentGain ){ // きっちりapparentGainだけ違っていれば
     // System.out.println(i);
     aList.add((int)i); // 解に加える
    }
   }
  }
  // System.out.println("-" + aList.size());
  int[] ret = new int[aList.size()];
  for( int i=0 ; i<aList.size() ; i++ ){
   ret[i] = aList.get(i);
  }
  Arrays.sort(ret);
  return ret;
 }

}

この問題では探索範囲をあらかじめ狭めておかないと2秒という制約にひっかかってしまいます。単なる二重ループなのですが、いくらか工夫が必要です。現在の体重の最大値はapparentGain/2+1程度で評価できます。それより大きい値では過去の体重が現在の体重-1としても、apparentGainを超えてしまうためです。例えばapparentGainが5のとき現在の体重は1~3までです。現在の体重を4とすると、4よりわずか1小さい3を過去の体重としても4^2-3^2 = 7 > 5なので、やはり解にはなりえません。

得点は164.37/250、1回のsubmitでシステムテストクリア。表示込みで200msecかかるケースもあるので、時間はギリギリ。中央値は約123点でした。

2012年5月11日金曜日

初めてのコンピュータサイエンス第3章解答

第3章の解答を上げます。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。

1

>>> 'Comp' 'Sci' # +がなくても文字列は結合される
'CompSci'
>>> 'Computer' + 'Science' # +を明示した方が読みやすい...
'ComputerScience'
>>> 'H20' * 3
'H20H20H20'
>>> 'C02' * 0 # 0回の繰り返しは空文字
''

2

>>> "They'll hibernate during the winter"
"They'll hibernate during the winter"
>>> '"Absolutely not," he said.'
'"Absolutely not," he said.'
>>> '"He said, \'Absolutely, not\'" recalled Mel.'
'"He said, \'Absolutely, not\'" recalled Mel.'
>>> 'hydrogen sulfide'
'hydrogen sulfide'
>>> 'left\right'
'left\right'

3

'A\nB\nC'

4

>>> len('')
0

5

>>> x = 3
>>> y = 12.5
>>> print 'The rabbit is %d' % x
The rabbit is 3
>>> print 'The rabbit is %d years old' % x
The rabbit is 3 years old
>>> print '%.1f is average' % y # .1fで小数点1桁まで表示する
12.5 is average
>>> print '%.1f * %d' % (y, x) # 複数の引数をとる場合は括弧で囲む
12.5 * 3
>>> print '%.1f * %d = %.1f' % (y, x, y * x)
12.5 * 3 = 37.5

6

>>> print "%.2f" % 34.5
34.50
>>> print "%.2e" % 34.5 # eは指数表示、.2で小数点第2位まで表示
3.45e+01
>>> print "%04d" % 8 # 0が0埋めを意味する
0008
>>> print "%-2d" % 8 # -が左詰めを意味する
8 

7

>>> num = float(raw_input("Please input number")) # 入力を求める画面が出るので3.14と入力
>>> print num
3.14

8

たとえば「文字列 + 整数」のようなデータに対し足し算を認めていないので、変数を+で結べないようにしている。'123' + 4 は文字列('1234')としてみるか、数値(127)としてみるかという複数の解釈が発生してしまうので、そのような問題も避けている。

9

文字列に負数をかけるという操作は無意味なものであり、0回かけた空文字列とは区別するべきという立場であればエラーにするべき。 ただし、そこに気をつけていれば、負数をかけることでエラーにならないことは処理が簡単になるというメリットもあると思われる。

2012年5月10日木曜日

初めてのコンピュータサイエンス第2章解答

Pythonの演習ということで、解答をあげてみます。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。

1

>>> 9 - 3
6
>>> 8 * 2.5 # 実数を含むので答えも実数
20.0
>>> 9 / 2
4
>>> 9 / -2 # 切捨てが入る -4.5 -> -5 になる
-5
>>> 9 % 2
1
>>> 9 % -2 # 剰余の符号は2番目の値の符号に依存する
-1
>>> -9 % 2
1
>>> 9 / 2.0
4.5
>>> 4 + 3 * 5 # 演算子の順位は通常の演算と同じ(足し算より掛け算優先)
19
>>> (4 + 3) * 5
35

2

xが-17のとき+xは-17であるべき。+1 * x と考えている。

3

>>> temp = 24
>>> temp = temp * 1.8 + 32
>>> temp
75.2

4

>>> x = 10.5
>>> y = 4
>>> x = x + y
>>> x
14.5
>>> y
4

5

x-xを最初に評価して0、次にx += 0を評価するのでxが3であれば、x = x + 0 = 3になる。

6

関数名は長すぎるとタイピングが面倒(IDEを利用すれば楽だが読みづらい)、短すぎると意味が何通りにも取れる恐れがある。 またコードを読むという観点で見たときには、関数名に含まれる英単語がわかる状態が望ましい。トレードオフの関係にある。 個人的にはfahr_to_cel、fahrenheit_to_celsius程度が望ましいと思われる。_to_を2にするのは英語圏オンリーならありかなと 思います。

7

# -*- encoding: utf-8 -*-
def convert_mileage(mpg):
    # 1米ガロン = 3.78541178 l
    # 1マイル = 1.609344 km
    return 3.78541178 * 100 / ( 1.609344 * mpg )

print convert_mileage(20)
print convert_mileage(40)

8

仮引数は関数が呼び出されるときに値が設定される変数で、実引数は関数を呼び出したときに実際に入れられる値。

9

c)の答えは30、d)の答えはconvert_mileage関数である。

def liters_needed(distance, fuelEfficiency):
    return distance * convert_mileage(fuelEfficiency) / 100

print liters_needed(150, 30)
print liters_needed(100, 30)

10

>>> pow(3, 7)
2187
>>> int(34.7)
34
>>> round(34.7)
35.0
>>> float(abs(-86))
86.0

2012年5月8日火曜日

TopCoder SRM383 Div2 250Pts

このTopCoderの問題はこちら で見ることができる(要TopCoder登録 & 問題文は英語)。問題文について説明する。

あなたは新しい家を建築中で、ある部屋に床板を敷こうとしている。設計師は床板のレイアウトをデザインしており、それに対し何枚のボードを買う必要があるか知りたいと思っている。各板は1単位の幅を持ち、すべて任意の正の整数の値をとり得る。部屋は長方形の形状をしており、板は壁とは平行に、1単位の正方形の格子の位置に配置するものとする。 layout[]という、床板のレイアウトを表す文字列が与えられる。i番目の文字列のj番目の要素は正方形の格子の(i, j)番目の位置を表しており、その内容は"-"または"|"になる。それらは床板の方向を表している。もし"-"という2文字がi番目の文字列に隣り合っていれば、それは東西方向の床板1枚を表す。同様に"|"については、jが同じで隣り合う配置であれば、南北方向の床板1枚を表すことになる。レイアウト通りに配置するときに必要となる床板の枚数を返せ。

public class FloorLayout {
 public int countBoards(String[] layout) {
  int nBoard = 0;
  nBoard += count(layout, '-');
  String[] transpose = new String[layout[0].length()]; // layoutを転置した後の文字列
  for( int i=0 ; i<layout[0].length() ; i++ ){
   StringBuilder sb = new StringBuilder();
   for( int j=0 ; j<layout.length ; j++ ){
    sb.append(layout[j].charAt(i));
   }
   transpose[i] = sb.toString();
   sb.delete(0, sb.length());
  }
  nBoard += count(transpose, '|');
  return nBoard;
 }
 // typeという文字の板が何枚必要になるか、平行方向についてのみカウント
 // "-"にはそのまま適用可能、"|"についてはlayoutを転置することで適用可能。
 private int count(String[] layout, char type){
  int nBoard = 0;
  for( int i=0 ; i<layout.length ; i++ ){
   char prev = ' ';
   for( int j=0 ; j<layout[0].length() ; j++ ){
    char c = layout[i].charAt(j);
    if( c == type ){
     if( prev != type ) nBoard++;
    }
    prev = c;
   }
  }
  return nBoard;
 }
}

得点は181.76/250、1回のsubmitでシステムテストクリア。中央値は約173点。

入門自然言語処理第1章メモ

Python、NLTKによる言語処理のための個人的tips。NLTKをインストールした上で以下の記事を読んでください。最新のバージョンでのインストールについてはこちらなどが参考になるでしょう。バージョンがあがったため、インストール方法に若干の変更があります。後々のことも考えて、これまでと同じくPyYAML、matplotlib、NumPyなども入れておきましょう(この記事では特にNLTK以外は必要にはなりませんが)。

単語の数え方

from nltk.book import *

# text6はMonty Python(Pythonという言語名の由来になった作品)
print len(text6) # 単語数(スペース区切り)のカウント
print len(set(text6)) # ユニークな単語数をカウント

語彙の多様性の計算、および簡単なメソッド作成

print len(text6)*1.0 / len(set(text6)) # 語彙の豊富さ

# 文章中の単語の多様性のメソッド
# メソッドにすることにより、同じことを繰り返す手間が省ける。というか、
# バグがあったときの修正も楽になるので、繰り返し利用するならメソッドにするべき。

# def メソッド名(引数): で始める。
def lexical_diversity(text):
    return len(text) * 1.0 / len(set(text))

# totalに対するcountの割合
def percentage(count, total):
    return 100.0 * count / total

リストの扱い方

# +はリストの結合
week = ['Mon', 'Tue', 'Wed', 'Thr', 'Fri'] + ['Sat', 'Sun']
print week
print sorted(week) # 内容で昇順にソート

prime = [2, 3, 5, 7]
prime.append(9) # appendは最後尾への結合
print prime # [2, 3, 5, 7, 9]

# 添え字によるアクセス
# 先頭を添え字0とするので3番目のデータにアクセス
print prime[2] # 5
# スライシング
# array[n:m]でarray[n]~array[m-1]を取り出す
print prime[1:3] # [3, 5]
# :の前半の添え字を省略すると、前半は0とみなされる
print prime[:2] # [2, 3]
# :の後半の添え字を省略すると、後半は配列の最後の添え字+1とみなされる
print prime[3:] # [7, 9] 

文字列の扱い方

lang = 'Python'
print lang[:3] # スライシングできる
print lang * 2 # 繰り返し
print 'Hello ' + lang + '!' # +による結合
# 複数行にわたる表記(改行も入る)
number = '''one
two
three'''
print number

リスト内包表記

from nltk.book import *

# text6の各単語をwとして、wの長さが10になるwの集合
word10 = [w for w in text6 if len(w) == 10]
print sorted(word10)[:10] # ソートした結果の先頭10語のみ出力

条件分岐

age = 26
if age < 12: # ageが12未満ならchildと表示
    print "child"
elif age < 20: # 20未満ならyoungと表示
    print "young"
else: # それ以外(この場合20以上になる)ならadultと表示
    print "adult"

2012年5月7日月曜日

2012年4月の学習記録

2012年4月に学習した主な本一覧。

大学生の微積分(pp.198~207)
演習が反復できてないせいか、一月ぶりに思い起こしてみたところ、記憶に定着していないですな。
大学生の線形代数(pp.98~165)
連立一次方程式の掃き出し法や行列式はある程度覚えたので省いて途中から。固有値の問題でも初見のものがあり、なかなか面白いです。
マスタリングTCP/IP(pp.1~58)
ネットワークの入門書ということで読んでおります。たとえ話が多いのが印象的。
一般化線形モデル入門(pp.1~79)
指数型分布族と一般化線形モデルのお話。Rを利用して演習しております。y=ax+b+eを拡張したものが一般化線形モデル。一般化線形モデルで利用できるモデルは正準形という指数型分布族の特殊な分布でないとダメだそうです。とはいえ、最小二乗法のように誤差は正規分布という強い仮定は必ずしも要らないわけで、適用範囲は広がっているのかなと思いました。この学習でロジスティック回帰を理解したい。
情報量統計学(pp.1~7)
AICの導出が書かれているということで、読んでみることに。まだ7ページなので特に感想は無し。
たのしいRuby(pp.1~50)
PythonとRubyのどちらを学習するべきかいまだに悩んでおります。日本語処理やWebアプリを書くだけならRubyが良さそうですが、データ解析となるとPythonの方がライブラリが充実しているイメージ。
詳解演習 線形代数(pp.68~82)
記憶への定着を目指して大学生の線形代数と同じような内容の箇所をひたすら解く。大学生の線形代数の問題よりは難しいかなと思います。
統計解析入門(赤平)(pp.70~88)
精読中。詳しく読むと、集合・位相論の本が読みたくなることもあります。閉包とか、よくわからない概念が出てくるもので...

フォロワー

ブログ アーカイブ

ページビューの合計