Pythonで競技プログラミング

qiita.com

私はpythonを使用してAtcoderに参加しているので、上の記事を参考にしつつ、pythonを使用して学んでいきます。

abs

絶対値を求める関数。abs(n)とすると実行できます。

abs(-100) #100
abs(20) # 20

absは、直線グラフ上などでの差を求める場合などによく使われる印象です。

string

文字列です。 Pythonでは、変数の宣言時に型を指定しなくてよいので、値をシングルクォートかダブルクォートで囲えば文字列になります。

a = 'aaa'
b = "bbb"

よく使う処理を以下に例示します。

#入力を文字列sとして受け取る
s = input()

#文字列sを出力する(最終的な回答を出力するときに使います)
print(s)

#文字列のs文字目
#以下の場合、文字列abcdeの0文字目であるaとなります
s = "abcde"
s[0]

#部分文字列。文字列sの、1文字目から2文字目を指します。
#[1:3]としたとき、開始はその地点を含むが、終了は含まないことに注意する
#例
s = "abcde"
s[1:3] # bc

#文字列sのサイズを返します。
s = "abcde"
len(s) #5

min/max

最小値と最大値を返します。 これも使用頻度は高いです。 引数にイテラブル(リストやセットなど)を渡すことで、最も値が小さい/大きい値を返します。

a = [1,2,3,4,5,6,7,8]
min(a) #1
max(a) #8

swap

2つの値を入れ替えます。 Pythonだと文法的に以下のように書くことで変数aとbの値を入れ替えることができます。

a = 5
b = 3
a, b = b, a #aが3に、bが5になる

gcd

最大公約数です。Pythonでは、fractionsモジュールをインポートして使います。

import fractions
fractions.gcd(32, 12) #4

reverse

配列の逆順の並び替えを行います。
逆順にする方法はいくつかあるのですが、代表的なものを2つ紹介します。

#リストのもつreverse()メソッドを使用した例。これはリストそのものの順序が変更されます。
a = [1,2,3,4,5,6]
a.reverse() #aが[6,5,4,3,2,1]になります。

一方で、もとのリストには影響を与えない組み込み関数のreversed()もあります。

a = [3,4,5,6,7]
b = reversed(a)

#元のリストは変化しないので、リストaは[3,4,5,6,7]のままとなります。
#reversed関数はイテレータを返却するので、以下のように使用できます。
for i in b:
    print(i)

sort

リストの並び替えを行います。 こちらも、reverseと同じく、リストそのものを変化させるか、並び替え後のリストを新たに返却する組み込み関数と両方があります。

a =  [3,6,8,2,0,1]
b = sorted(a)
#bは[0, 1, 2, 3, 6, 8]となるが、aは[3, 6, 8, 2, 0, 1]のまま

#以下のようにメソッドを呼び出すと、aそのものが並び替えされます
a.sort()

list

後述するsetdictなどと同様に、値(オブジェクト)の集まりを表します。
値のソートや、要素へのインデックスアクセスができます。

a = [1, 2, 3, 4, 5]
b = ['a', 'b', 'c']

リストと同じように、スライスを使用することで範囲アクセス等もできます。

list_b = a[1:] #[2, 3, 4, 5]
list_c = a[2:5] #[3, 4, 5]

stack

これから述べるスタックとキューについては、公式ドキュメントにもあるように、前述したリストを用いて実現できます。

スタックは、代表的なデータ構造の一つで、いわゆるLIFO(last-in, first-out)を実現します。最後に追加された要素が最初に取り出されます。
リストのメソッドであるappend()を呼び出すことでリストの末尾に要素を追加し、pop()を呼び出すことで末尾の要素を取り出す(削除する)ことで、スタックと同様のことができるようになります。

stack = [3, 4, 5]
stack.append(6)
stack.append(7)
#[3, 4, 5, 6, 7]

stack.pop()
#[3, 4, 5, 6]

stack.pop()
#[3, 4, 5]

stack.pop()
#[3, 4]

queue

キューも代表的なデータ構造の一つで、こちらはFIFO(first-in, first-out)、つまり最初に入れた要素を最初に取り出すデータ構造です。(待ち行列のイメージですね。)
キューをPythonで実現するには、collectionsモジュールのdequeを使用します。

from collections import deque
queue = deque([1, 2, 3, 4, 5])
queue.append(6)
#[1,2,3,4,5,6]

queue.popleft() #pop()とpopleft()があるが、キューを実現する場合、popleft()を使用する。
#[2,3,4,5,6]

priority_queue

優先度付きキューです。公式ドキュメントにあるように、heapqを使用します。
優先度付きキューは、最小値に高速にアクセスしたいときなどに使用します。

import heapq

#リストを優先度付きキューにする
a = [3,1,7,4,0]
heapq.heapify(a)

#最小値の取り出し
heapq.heappop(a)

#要素の挿入
heapq.heappush(a, -3)

dict

キーと値を紐づけて保持するデータ構造です。

d = {}
d['a'] = 1
d['b'] = 2

d['a'] #1

#なお、指定したキーがdictにない場合、エラーとなるので注意
dict['c'] #keyErrorが発生

また、dictをループで使用する場合、'values()'や、'items()'を使用します。

#キーをループさせる
for s in d:
    print(s)

#値をループさせる
for v in d.values():
    print(v)

#キーと値のペアでループさせる
for k, v in d.items():
    print(k + ' is ' + str(v))

また、pythonではCounterというdictのサブクラスもあり、こちらも併せて紹介します。
Counterは、値をカウントする際に便利なクラスです。例えば以下のように使えます。

from collections import Counter
c = Counter('aaabbc')
c['a'] #3
c['b'] #2
c['c'] #1
c['d'] #0

上記のように、文字列を引数としてCounterオブジェクトを生成すると、それぞれの文字の個数をカウントして、文字:カウント数の形式の辞書を生成できます。
また、c['d']のように存在しないキーにアクセスしても、keyErrorを返すことなく、0が返されます。

defaultdict

Pythonでは、さらにもう一つ便利なdefaultdictというdictのサブクラスが存在します。 名前の通り、キーに紐づける値のデフォルト値を定義することができます。例えばカウンタのようなものをdictで表現するときに、defaultdictオブジェクトを生成するときの引数を'int'にすることで、初期値0となるdictが生成できます。

from collections import defaultdict

d = defaultdict(int)
d['a'] += 1

上記の例では、defaultdictオブジェクトのdを生成した時点ではキーaはまだdictに登録されていませんが、デフォルト値としてint()の0が設定されるため、KeyErrorとならずにd['a']を呼び出すことができます。

bisect(二分探索)

リストをソートされた順序に保ちつつ、リストへの挿入や、削除ができます。
内部的に二分法を使用しています。(公式ドキュメント

import bisect
#6をあえて除いたリスト
a = [1,2,3,4,5,7,8,9]
l = bisect.bisect_left(a, 6)
r = bisect.bisect_right(a, 6)

#6を挿入しようとした場合、インデックス位置は5となる。
print(l) #5
print(r) #5

#既に存在する値(3)を挿入しようとした場合、bisect_leftか、bisect_rightかで挿入位置が変わる
l = bisect.bisect_left(a, 3)
r = bisect.bisect_right(a ,3)
print(l) #2
print(r) #3

set

集合を扱います。
setは、要素の重複を許しません。
そのため、同じ要素を追加すると、要素数に変化はありません。

s = set()
s.add(1)
s.add(1) #すでにある要素を追加する

s.count() #1
#要素は重複して保持されないため、カウントは1となる

permutations(順列)

itertools.permutations(iterable, r = None)を使用することで、iterableの要素からなる長さrの順列を連続的に返します。
以下に例を示します。

import itertools

a = [1, 2, 3]

it = itertools.permutations(a)

for l in it:
  print(l)

結果

(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

combinations(組み合わせ)

'itertools.combinations(iterable, r)'を使用することで、長さrの部分列となる組み合わせを求めることができます。

import itertools

s = 'abcd'

#sから2個ずつ文字を選んだ組み合わせの総数を求めます
combi = itertools.combinations(s, 2)
for l in combi:
    print(l)

結果

('a', 'b')
('a', 'c')
('a', 'd')
('b', 'c')
('b', 'd')
('c', 'd')