【競プロ】AtCoderを始めるためのPythonの基本

coffee-and-note-on-desktop プログラミング

コメント

「#」を使うことで、その行はコメントになります。

複数行のコメントは「”””」で囲みます。

# コメントになる


"""
ここはコメントになります。
ここもコメントになります。
"""

出力

出力は「print()」を使います。

print(1)		# => 1
print(0.8)		# => 0.8
print('a')		# => a
print('Python')	# => Python

区切り文字の変更

複数の引数を渡すこともできます。各引数は空白で区切られて出力されます。

「sep」を指定することで、空白以外で区切ることもできます。

a = 'Hello'
b = 'World'

# 空白区切り
print(a, b)			 	# => Hello World

# 空白ではなく、「,」で区切る
print(a, b, sep=',')	# => Hello,World

末尾文字の変更

print() はデフォルトでは、出力の末尾で改行します。

「end」を指定することで、出力の末尾を変更できます。

# 改行させない
print(Hello, end='')
print(World)

# => HelloWorld

フォーマット済み文字列リテラル

文字列の頭に「f」つけることで、変数を簡単に埋め込めます。

埋め込む変数は「{}」で囲みます。

name = 'Alice'
age = 25
print(f'{name} is {age} years old.')	# => Alice is 25 years old.

小数点以下の桁数も指定できます。

x = 1.23456
print(f'{x:.2f}')	# => 1.23
print(f'{x:.10f}')	# => 1.2345600000

入力

入力は「input()」を使います。

input() は、入力された1行を文字列として受け取ります。

# 文字列で受け取る
s = input()

# 整数で受け取る
n = int(input())

# 浮動小数点数で受け取る
f = float(input())

スペース区切り

A B
# 文字列で受け取る
a, b = input().split()

# 整数で受け取る
a, b = map(int, input().split())

# 浮動小数点数で受け取る
a, b = map(float, input().split())

スペース区切りをリストに

A1 A2 ... AN
# 文字列で受け取る
a = list(input().split())

# 整数で受け取る
a = list(map(int, input().split()))

# 浮動小数点数で受け取る
a = list(map(float, input().split()))

複数行の入力をリストに

A1
A2
:
AN
# 文字列で受け取る
a = [input() for _ in range(N)]

# 整数で受け取る
a = [int(input()) for _ in range(N)]

# 浮動小数点数で受け取る
a = [float(input()) for _ in range(N)]

複数行のスペース区切の入力をリストに

X1 Y1
X2 Y2
:
XN YN
# 文字列で受け取る
a = [list(input().split()) for _ in range(N)]

# 整数で受け取る
a = [list(map(int, input().split())) for _ in range(N)]

# 浮動小数点数で受け取る
a = [list(map(float, input().split())) for _ in range(N)]

演算子

算術演算子

算術演算子には、次のようなものがあります。

  • +:加算
  • -:減算
  • *:乗算
  • **:べき乗
  • /:除算(浮動小数点)
  • //:除算(小数点以下切り捨て)
  • %:剰余
print(1 + 2)	# => 3
print(3 - 2)	# => 1
print(2 * 3)	# => 6
print(2 ** 3)	# => 8
print(4 / 2)	# => 2.0
print(5 / 2)	# => 2.5
print(5 // 2)	# => 2
print(5 % 2)	# => 1

文字列の結合には「+」を使います。

a = 'Hello'
b = 'Python'
c = a + b
print(c)	# => HelloPython

比較演算子

比較演算子には、次のようなものがあります。

  • >:より大きい
  • >=:より大きいか等しい(以上)
  • <:より小さい
  • <=:より小さいか等しい(以下)
  • ==:等しい
  • !=:等しくない
n = 80

# 複数の値を比較できる
print(60 < n < 100)	# => True

# 文字列の比較
print('a' < 'b')	# => True
print('a' < 'A')	# => False

論理演算子

論理演算子には、次のようなものがあります。

  • and:論理積
  • or:論理和
  • not:否定
print(True and False)	# => False
print(True or False)	# => True
print(not True)			# => False

条件分岐

「if」を使います。

if 式1:
    処理1
elif 式2:
    処理2
else:
    処理3
a = 2
if a % 2 == 0:
    print('偶数です')
else :
    print('奇数です')


x = 75
if x > 80:
    print('ここは実行されません。')
elif x > 50:
    print('ここは実行されます。')
else:
    print('ここは実行されません。')


# まとめて書くこともできます
if 50 < x <= 100:
    print('ここは実行されます。')
else:
    print('ここは実行されません。')

繰り返し

for

「for」は、次のように使います。

for 変数 in オブジェクト:
    処理

range() を使うことで、指定の回数繰り返すことができます。

range(start, stop[, step])

オブジェクトに、文字列やリストを渡せば、その要素について繰り返すこともできます。

# 3回繰り返す
for i in range(3):
    print(i)

# 実行結果
"""
0
1
2
"""


# 文字列の繰り返し
s = 'Python'
for c in s:
    print(c)

# 実行結果
"""
P
y
t
h
o
n
"""


# リストの繰り返し
fruits = ["apple", "banana", "orange"]
for fruit in fruits:
    print(fruit)

# 実行結果
"""
apple
banana
orange
"""

while

「while」は、次のように使います。

while 条件式:
    処理
i = 0
while i < 3:
    print(i)
    i += 1

# 実行結果
"""
0
1
2
"""

文字列

文字列は「’」または「”」で囲みます。

# unicode ⇔ 文字
print(ord('A'))  # => 65
print(chr(65))  # => A


# 0 埋め
print('1'.zfill(5))  # => 00001
print('123'.zfill(5))  # => 00123


# 大文字に変換
a = 'abc'
print(a.upper())  # => ABC


# 小文字に変換
b = 'ABC'
print(b.lower())	# => abc


# スライス
c = '0123456'
print(c[2:])	# => 23456
print(c[2:4])	# => 23
print(c[:4])	# => 0123

# 文字列の反転
print(c[::-1])	# => 6543210


# 何個あるか
d = 'abbccc'
print(d.count('a'))	# => 1
print(d.count('b'))	# => 2
print(d.count('c'))	# => 3


# 置き換える
e = 'abcabc'
print(e.replace('a', 'A'))	# => AbcAbc

in を使えば、文字列の中に部分文字列が存在するか確認できます。

存在しないか確認は not in を使います。

s = 'abcde'
t = 'bcd'

if t in s:
    print('部分文字列です')
else:
    print('部分文字列ではありません')


if 'c' not in s:
    print('部分文字列ではありません')
else:
    print('部分文字列です')


# 実行結果
"""
部分文字列です
部分文字列です
"""

list

python の list は、ほかのプログラミング言語の配列のように使えます。

リストは、[] で囲みます。

a = ['one', 'two', 'three']
print(len(a))	# => 3
print(a[0])		# => one
print(a[-1])	# => three
a.append('four')
print(len(a))	# => 4
print(a)		# => ['one', 'two', 'three', 'four']

b = [0] * 3
print(b)		# => [0, 0, 0]


# 要素を追加する
c = []
c.append(1)
c.append(7)
c.append(5)
c.append(6)
c.append(2)
print(c)		# => [1, 7, 5, 6, 2]


# 最小・最大の要素
print(min(c))	# => 1
print(max(c))	# => 7


# 並び替え
print(sorted(c))	# => [1, 2, 5, 6, 7]
print(c)			# => [1, 7, 5, 6, 2]
c.sort()
print(c)			# => [1, 2, 5, 6, 7]


# 要素の合計
d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(sum(d))  # => 55

# list.index(x[, start[, end]])
# リストの中でxと等しい値を持つ最初の要素の位置をゼロから始まる添え字で返す。
print(d.index(5))  # => 4

空のネストしたリストを作る方法です。

a = [[] for _ in range(5)]
print(a)	# => [[], [], [], [], []]

a[0].append(1)
a[0].append(2)
a[3].append(3)
print(a)	# => [[1, 2], [], [], [3], []]

set

集合を表します。

set は、重複を許さない要素の集合です。

print(set('aaa'))	# => {'a'}
print(set('aab'))	# => {'a', 'b'}
print(set('abc'))	# => {'a', 'b', 'c'}

a = set('aab')
print(len(a))		# => 2


# set の宣言
b = set()
b.add('A')
b.add('B')
b.add('A')
print(b)			# => {'A', 'B'}

# 要素の削除
b.remove('B')
print(b)			# => {'A'}


# {}でも set の宣言ができる
c = {2, 4, 1, 3}

# 最小・最大の要素
print(min(c), max(c))	# => 1 4

dict

辞書を表します。

Key と Value を対応付けて管理できます。

a = {'one': 1, 'two': 2, 'three': 3}
print(a['two'])		# => 2

# dict の要素について処理
for key,value in a.items():
    print(key, value)

# 実行結果
"""
one 1
two 2
three 3
"""
    

b = {}
b['one'] = 1
b['five'] = 5
print(b)		# => {'one': 1, 'five': 5}


c = {'B': 1, 'A': 3, 'C': 2}
# key で並び替え
print(sorted(c.items(), key=lambda x: x[0]))	# => [('A', 3), ('B', 1), ('C', 2)]

# value で並び替え
print(sorted(c.items(), key=lambda x: x[1]))	# => [('B', 1), ('C', 2), ('A', 3)]


# 空のdict
d = dict()
for i in range(5):
    if i not in d:
        d[i] = 1
    else:
        d[i] += 1
        
for i in d.values():
    print(i)
    
# 実行結果
"""
1
1
1
1
1
"""

辞書の中にリストを作る方法です。

# 空のdict
d = dict()
for i in range(2):
    # 初めのとき
    if i not in d:
        d[i] = []
    
    # 要素の追加
    for j in range(3):
        d[i].append(j)
        
print(d)

# 実行結果
"""
{0: [0, 1, 2], 1: [0, 1, 2]}
"""

関数

関数は def を使います。

def add(a, b):
    return a + b

print(add(1, 2))	# => 3
print(add(5, 10))	# => 15

再帰関数

Python では、再帰関数の上限値が設定されているため、多くの再帰をするときは上限値(スタックサイズ)を変更します。

スタックサイズを変更

import sys
sys.setrecursionlimit(10**6)

メモ化

from functools import lru_cache
@lru_cache(maxsize=None)    # このデコレータを関数の頭に

グラフ

n, m = map(int, input().split())
a = [[] for _ in range(n)]

for _ in range(m):
    u, v = map(int, input().split()) 
    a[u].append(v)
    a[v].append(u)

幅優先探索

幅優先探索の基本的なコードです。

# collections モジュールから deque クラスをインポートする
from collections import deque

# キューの宣言
queue = deque()
# n 個の地点すべてを未探索に
distance= [-1] * n

# 探索開始地点をキューに追加する
queue.append(0)
# 探索開始地点を探索済みに
distance[0] = 0

# キューが空になるまで繰り返す
while queue:
    # キューの先頭の要素を取り出す
    v = queue.popleft()

    # 取り出した地点から行ける地点について繰り返す
    for next_v in graph[v]:
        # 行ける地点が探索済みならスキップ
        if distance[next_v] != -1:
            continue

        # 行ける地点をキューに追加する
        queue.append(next_v)
        # 行ける地点を探索済みにして距離を格納
        distance[next_v] = distance[v] + 1

深さ優先探索

深さ優先探索の基本的なコードです。

# スタックサイズの変更
import sys
sys.setrecursionlimit(10**6)

# 深さ優先探索
def dfs(v):
    # v 地点を探索済みに
    seen[v] = True

    # 取り出した地点から行ける地点について繰り返す
    for next_v in graph[v]:
        # 行ける地点が探索済みならスキップ
        if seen[next_v]:
            continue

        # 行ける地点について再帰的に探索
        dfs(next_v)

# n 個の地点すべてを未探索に
seen = [False] * n

# 0地点から深さ優先探索
dfs(0)

Union-Find

Union-Find を使えば、グループ分けを効率的に管理できます。

class UnionFind():
    # 初期化
    def __init__(self, n):
        self.parent = [-1] * n
        self.size = [1] * n

    # x の根を求める
    def root(self, x):
        # x が根のとき
        if self.parent[x] == -1: 
            return x

        # 経路圧縮
        self.parent[x] = self.root(self.parent[x])
        return self.parent[x]

    # x と y の根が同じか
    def is_same(self, x, y):
        return self.root(x) == self.root(y)

    # x と y のグループを併合する
    def unite(self, x, y):
        # x と y の根を取得
        rootX = self.root(x)
        rootY = self.root(y)

        # x と y が同じグループのときは何もしない
        if rootX == rootY:
            return

        # union by size( y のサイズが小さくなるように調整)
        if self.size[rootX] < self.size[rootY]:
            rootX, rootY = rootY, rootX

        # y の親を x にする
        self.parent[rootY] = rootX

        # rx 側の siz を調整する
        self.size[rootX] += self.size[rootY]
        return
  
    # x を含む根付き木のサイズを求める
    def get_size(self, x):
        return self.size[self.root(x)]

Union-Findは、次のように使います。

uf = UnionFind(10)
uf.unite(0,1)

Union-Findについては、C++での解説になりますが、次の記事で解説しています。

bit 全探索

# bit 全探索
for i in range(2**n):
    for j in range(n):
        if i & (1 << j):
            選ばれているときの処理

順列全探索

順列全探索には、itertools ライブラリを使うことで簡単に実装できます。

import itertools

# 順列全探索
for permutation in itertools.permutations(A):
    順列に対する処理

二分探索

めぐる式二分探索は次のようになります。

def is_ok(index, key):
    if a[index] >= key:
        return True
    else:
        return False

def binary_search(key):
    ng = -1
    ok = len(a)
    while abs(ok - ng) > 1:
        mid = (ok + ng) // 2
        if is_ok(mid, key):
            ok = mid
        else:
            ng = mid
    return ok

bisect ライブラリを使うことで、二分探索をすることもできます。

bisect_left() と bisect_right() があり、配列と値を引数として渡します。

import bisect

a = [1, 2, 3, 3, 4, 5, 5, 5, 6] 

print(bisect.bisect_left(a, 3))		# => 2
print(bisect.bisect_right(a, 3))	# => 4

print(bisect.bisect_left(a, 0))		# => 0
print(bisect.bisect_left(a, 10))	# => 9

深いコピー

copy ライブラリをインポートします。

import copy

a = [1, 2]
b = copy.deepcopy(a)

優先度付きキュー

キューから最も小さい要素について操作ができます。

heapq ライブラリをインポートします。

import heapq

# 空のリストを作成
h = []

# h に要素を追加
heapq.heappush(h, 3)
heapq.heappush(h, 1)
heapq.heappush(h, 4)
heapq.heappush(h, 2)

print(h)  # =>  [1, 2, 4, 3]

# 最小の要素が取り出される
a = heapq.heappop(h)
print(a)  # => 1

b = heapq.heappop(h)
print(b)  # => 2

c = heapq.heappop(h)
print(c)  # => 3

d = heapq.heappop(h)
print(d)  # => 4

参考

二分探索アルゴリズムを一般化 〜 めぐる式二分探索法のススメ 〜 – Qiita

Union-Find の実装 – アルゴ式

タイトルとURLをコピーしました