理系母の趣味はプログラミング

理系院卒、メーカー技術職の二児の母が、PythonやVBAで色々と作ってアップしていくブログです。

基本情報技術者アルゴリズムの問題をPythonでコーディングしてみた【令和元年秋】

【26日目】

Pythonの基本文法に慣れてきた今日この頃。

そろそろ参考書外で何か作ってみようと思い、
基本情報技術者試験の試験勉強も兼ねて
最も苦手とするアルゴリズムの過去問をPythonで書いてみました!
Pythonの文法の練習にもなるし
問題中に入出力の例があって、確かめやすいのも良き!
プログラムの構成も真似すればいいので、
初心者の私にはうってつけだね。

ということで、最新の問題、令和元年秋期

過去問PDF「出典:令和元年度 秋期 基本情報技術者試験 午後 問8」


プログラム1&2

import logging
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(message)s')

Mask = dict() #文字A~Zに対応するビットマスク

def index(alphabet):
    #アルファベット→数字変換(問題文の関数Index)
    alpha2num = lambda c: ord(c) - ord('A') + 1
    return alpha2num(alphabet)

def generate_bit_mask(Pat):

    PatLen = len(Pat)

    for i in range(1,27): #range関数では,この場合27は含まない
        global Mask
        Mask[i] = 0B0 #初期化.二進数ビット表記のため、0Bをつける

    for i in range(0,PatLen): #pythonの要素番号は0から
        Mask[index(Pat[i])] = (0B1 << i)|Mask[index(Pat[i])]
        #"1"Bを(i-1)ビットだけ論理左シフトした値とMask[index(Pat[i])]の論理和

    for i in range(1,4):
       print("Mask[{}]".format(i),bin(Mask[i])) #設問1-a Mask[2]確認用
    
    return PatLen

def bitap_Match(Text,Pat):
    
    TextLen = len(Text)
    PatLen = generate_bit_mask(Pat)
    Status = 0B0
    Goal = 0B1 << PatLen-1 #"1"BをPatLen-1だけ論理左シフトした値

    logging.debug('設問2確認用')

    for i in range(0,TextLen):
        Status = (Status << 1)|0B1 #←α
        Status = Status & Mask[index(Text[i])] #←β

        logging.debug('i = {}, Mask[index(Text[i])] = {}, Status = {}'
                      .format(i+1, bin(Mask[index(Text[i])]),bin(Status)))
        #設問2用。i+1して対応付けしやすくした。
        
        if Status & Goal != 0B0:
            return ( i - PatLen + 1)+1
        #Text[]の要素番号に合わせるため+1する。(Pythonは0から)

    return (-1)


Text = "AACBBAACABABAB"
Pat = "ACABAB"

print(bitap_Match(Text,Pat))        

出力結果

Mask[1] 0b10101
Mask[2] 0b101000
Mask[3] 0b10
2020-04-17 11:47:01,858 - DEBUG - 設問2確認用
2020-04-17 11:47:01,858 - DEBUG - i = 1, Mask[index(Text[i])] = 0b10101, Status = 0b1
2020-04-17 11:47:01,874 - DEBUG - i = 2, Mask[index(Text[i])] = 0b10101, Status = 0b1
2020-04-17 11:47:01,874 - DEBUG - i = 3, Mask[index(Text[i])] = 0b10, Status = 0b10
2020-04-17 11:47:01,874 - DEBUG - i = 4, Mask[index(Text[i])] = 0b101000, Status = 0b0
2020-04-17 11:47:01,890 - DEBUG - i = 5, Mask[index(Text[i])] = 0b101000, Status = 0b0
2020-04-17 11:47:01,890 - DEBUG - i = 6, Mask[index(Text[i])] = 0b10101, Status = 0b1
2020-04-17 11:47:01,890 - DEBUG - i = 7, Mask[index(Text[i])] = 0b10101, Status = 0b1
2020-04-17 11:47:01,905 - DEBUG - i = 8, Mask[index(Text[i])] = 0b10, Status = 0b10
2020-04-17 11:47:01,905 - DEBUG - i = 9, Mask[index(Text[i])] = 0b10101, Status = 0b101
2020-04-17 11:47:01,905 - DEBUG - i = 10, Mask[index(Text[i])] = 0b101000, Status = 0b1000
2020-04-17 11:47:01,905 - DEBUG - i = 11, Mask[index(Text[i])] = 0b10101, Status = 0b10001
2020-04-17 11:47:01,921 - DEBUG - i = 12, Mask[index(Text[i])] = 0b101000, Status = 0b100000
7

過去問のプログラムと異なる点はコメントとして記載しています。
Python化による主な変更点は下記

  • 二進数ビットの表記は、数字の先頭に0b(0Bでも可)を付ける。
  • 要素番号が0から始まるため、ループ回数の数字も0始まり。

また、設問1、2の回答が確認できるように、PrintとloggingによるDEBUGを追加しています。

ちなみにTextとPatには過去問の値が入っていますが、変更させてみてもOKです。

プログラム3

Mask = dict() #文字A~Zに対応するビットマスク

def index(alphabet):
    #アルファベット→数字変換(問題文の関数Index)
    alpha2num = lambda c: ord(c) - ord('A') + 1
    return alpha2num(alphabet)

def generate_bitmask_regex(Pat):

    OriginalPatLen = len(Pat)
    PatLen = 0
    Mode = 0

    for i in range(1,27):
        global Mask
        Mask[i] = 0B0

    for i in range(0,OriginalPatLen):
        if Pat[i] == "[":
            Mode = 1
            PatLen = PatLen + 1
        elif Pat[i] == "]":
            Mode = 0
        else:
            if Mode == 0:
                PatLen = PatLen + 1
            Mask[index(Pat[i])] = (0B1 << (PatLen - 1))|Mask[index(Pat[i])]
            
    return(PatLen)
    
print(generate_bitmask_regex("AC[BA]A[ABC]A")) #hの答え
print(bin(Mask[1])) #gの答え
print(generate_bitmask_regex("AC[B[AB]AC]A"))
print(bin(Mask[1])) #iの答え

出力結果

6
0b111101
7
0b1011001

設問3の確認用でprint出力しています。

以上です。
結構時間かかったよ!

もっとこう書けばいいのに!みたいなコメント大歓迎です!!

それではまた^^