代々木公園のアジサイとバラ

ご覧頂きまして、誠にありがとうございます。
写真スライドショーが作れる動画編集ソフトを使って、YouTubeTikTokThreadsにUPしてます。

梅雨時、雨粒に濡れた紫陽花と薔薇を撮影。
カメラはOLYMPUSのミラーレス一眼です。

この日、別のところで撮影する予定でしたが、時間外になってしまい急きょ代々木公園へ。素敵な写真が撮れましたので、早速写真ムービーにしてYouTubeにUPしました。

※ 音量注意 ※

●YouTube

● TikTok

動画の中から写真を掲載致します。

OLYMPUS DIGITAL CAMERA

紫陽花も薔薇も、色鮮やかさと瑞々しさが溢れて撮影出来ました。

今日も見て下さって、ありがとうございました (=^x^=)

写真の投稿を始めました。
(写真AC)のプロフィールページです。

TikTok始めました。
始めた理由は、TikTokの仕組みに興味を持ったからです。若い方限定のSNSなので、自分には無理だと思っていたのですが、他のSNSが時間に影響を受ける仕組みに対してTikTokは時間に影響を受けないループ型なので、良い動画であれば過去の動画も見て頂けるという仕組みに興味を持って始めました。TikTokは、Twitterが使える方なら多分すぐ慣れると思いますし、動画編集に至っては、YouTubeの100倍以上楽です。

インスタ再開しました。

写真のアンケートを実施しております。
宜しかったらご回答頂けますと、大変励みになります(=^x^=)

■ 関連記事 ■

自己紹介


息抜きに、写真で癒し(=^x^=)に戻る

初めてのPhotoshop

写真素材素材【写真AC】

paiza レベルアップ問題集 「STEP: 10 階乗の末尾に 0 はいくつ付く?」をPythonとGASで解いてみた

この記事を読むことで、PythonとGASでループを使って階乗の計算とその計算結果の末尾に「0」がいくつ付くのかを求めます。
階乗の計算はforループを使い、末尾の「0」はPythonでは文字列に変換して求めてからwhileループで末尾の0の数をリストを反転して求め、GASでは10と2×5がいくつ含まれているのかwhileループを使って求めます。

このコーナーでは、学習コンテンツpaizaラーニングレベルアップ問題集をPythonとGASの両方で解いて全コードの解説をしています。
PythonとGASの両方のコードを用いて、全コード及び部分的にも可能な限り詳細に記載いたしました。

GASはスプレッドシートを使っています。
GASはGoogle Apps Scriptと言って、JavaScriptの文法をベースにしているので、JavaScriptの学習中の方にもお役立て出来るかも知れません。

サイトマップはこちらから

paizaレベルアップ問題集でPythonとGASを解いて見たに戻る
メインメニューに戻る
Python自作サンプル
GASサンプル
基本情報技術者試験

paizaでの解答はPythonで行いましたが、この記事ではPythonのコードと共に、同じ問題を現在学習中のGASだったらどう解くのか、スプレッドシートでバインドして作ってみました。

階乗の末尾に 0 はいくつ付く? (paizaランク C 相当)

問題:
整数 N が与えられます。
N の階乗 N! の末尾に 0 がいくつ付くか求め、出力してください。

この記事では、下記の入力例1の場合を例にして、整数N=100の階乗を求め、その計算結果100!の末尾に「0」がいくつ付くかを求めて行きます。

入力例1
100

出力例1
24

ではまず、Pythonで解いてみます。

今回は、paiza.ioを使って解きます。paiza.ioの使い方はこちらから。

■ Pythonでの解き方 ■

下準備として、paiza.ioにこの様に入力します。
(入力例1をそのままioにコピーしただけ。)

手順として、

1:Nを標準入力で取り込む

2:階乗の計算結果factを1で初期化する


3:ループを使ってNの階乗N!を変数factに求める
階乗の計算で乗算する数をmultに格納する


4:factが膨大な数になり、通常の10で割っていって0の数を求める方法が適用出来ない為、文字列に変換する


5:末尾の’0’を求めるため、文字列を逆順にする


6:’0’の数を数える変数zeroを0で初期化する


7:whileループで文字列のfactのi番目が’0’というの条件を満たす間、ループを回して’0’の数を数える変数zeroをインクリメントする


8:zeroを表示

で、行います。

まずは、プログラムの各変数の動きを追いやすいように、トレースのio出力結果と、トレースのコードを添えます。

100!は、100×99×98×97×・・・×4×3×2×1で求まります。

97まで掛けたログです。

途中、飛ばします。

1まで掛けたログです。

とても膨大な数になりましたので、画像は一部のみを切り取りました。

この計算結果factは膨大すぎてそのままでは10で割って0の数を数えるということが出来ない為、文字列に変換しました。
Strを使って、文字列に出来ます。

fact=str(fact)

問題文によると、文字列の末尾から’0’を数えるので、上の画像の文字列を反転しました。文字列のリストとして反転してから数えるので、このようなコードになりました。

fact=list(reversed(fact))

その後、文字列の先頭から’0’を数えていくので、whileループでリストfact[i]=’0’の時に、変数zeroをインクリメントするコードを書きました。

Fact[0]からfact[4]までのトレースです。

途中、省略します。

求めた0の個数です。

ここまでのトレースのコードです。

#Nを標準入力で取り込む
N=int(input())


#階乗の計算結果factを1で初期化する
fact=1


#ループを使ってNの階乗N!を変数factに求める
#階乗の計算で乗算する数をmultに格納する
print('<<<forループに入ります。>>>')

for i in range(N):
    print('計算前のfact:'+str(fact))
    mult=N-i
    print('fact×「'+str(mult)+'」を計算する')
    fact*=mult
    print('計算後のfact:【'+str(fact)+'】')
    print('------------------')
    
print('<<<forループを抜けました。>>>')    

#factが膨大な数になり、通常の10で割っていって0の数を求める方法が適用出来ない為、文字列に変換する
fact=str(fact)
print('文字列に変換したfact')
print(fact)

#末尾の'0'を求めるため、文字列を反転する
fact=list(reversed(fact))
print('文字列を反転したfact')
print(fact)

#'0'の数を数える変数zeroを0で初期化する
zero=0

#whileループで文字列factのi番目が'0'というの条件を満たす間、ループを回して'0'の数を数える変数zeroをインクリメントする
print('<<<whileループに入ります。>>>')

i=0  #whileループの場合、ループの変数の初期化も忘れない!!
print('zeroの初期値'+str(zero))
while(fact[i]=='0'):
    print('fact['+str(i)+']=「0」なのでzeroをインクリメントする')
    zero+=1
    print('zero:'+str(zero))
    i+=1 #ループの変数のインクリメントを忘れない!!これを忘れると無限ループになる!!
    print('--------------')

print('<<<whileループを抜けました。>>>')    
    

#zeroを表示
print(zero)

このままでは、出力結果である出力例1に対して冗長なコードが含まれているので、解答以外のprint文をコメントアウトします。


#Nを標準入力で取り込む
N=int(input())


#階乗の計算結果factを1で初期化する
fact=1


#ループを使ってNの階乗N!を変数factに求める
#階乗の計算で乗算する数をmultに格納する
#print('<<<forループに入ります。>>>')

for i in range(N):
    #print('計算前のfact:'+str(fact))
    mult=N-i
    #print('fact×「'+str(mult)+'」を計算する')
    fact*=mult
    #print('計算後のfact:【'+str(fact)+'】')
    #print('------------------')
    
#print('<<<forループを抜けました。>>>')    

#factが膨大な数になり、通常の10で割っていって0の数を求める方法が適用出来ない為、文字列に変換する
fact=str(fact)
#print('文字列に変換したfact')
#print(fact)

#末尾の'0'を求めるため、文字列を反転する
fact=list(reversed(fact))
#print('文字列を反転したfact')
#print(fact)

#'0'の数を数える変数zeroを0で初期化する
zero=0

#whileループで文字列factのi番目が'0'というの条件を満たす間、ループを回して'0'の数を数える変数zeroをインクリメントする
#print('<<<whileループに入ります。>>>')

i=0  #whileループの場合、ループの変数の初期化も忘れない!!
#print('zeroの初期値'+str(zero))
while(fact[i]=='0'):
    #print('fact['+str(i)+']=「0」なのでzeroをインクリメントする')
    zero+=1
    #print('zero:'+str(zero))
    i+=1 #ループの変数のインクリメントを忘れない!!これを忘れると無限ループになる!!
    #print('--------------')

#print('<<<whileループを抜けました。>>>')    
    

#zeroを表示
print(zero)

スッキリするように、コメントアウトした部分を省いたコードです。


#Nを標準入力で取り込む
N=int(input())


#階乗の計算結果factを1で初期化する
fact=1


#ループを使ってNの階乗N!を変数factに求める
#階乗の計算で乗算する数をmultに格納する
for i in range(N):
    mult=N-i
    fact*=mult


#factが膨大な数になり、通常の10で割っていって0の数を求める方法が適用出来ない為、文字列に変換する
fact=str(fact)


#末尾の'0'を求めるため、文字列を反転する
fact=list(reversed(fact))


#'0'の数を数える変数zeroを0で初期化する
zero=0


#whileループで文字列factのi番目が'0'というの条件を満たす間、ループを回して'0'の数を数える変数zeroをインクリメントする
i=0  #whileループの場合、ループの変数の初期化も忘れない!!
while(fact[i]=='0'):
    zero+=1
    i+=1 #ループの変数のインクリメントを忘れない!!これを忘れると無限ループになる!!


#zeroを表示
print(zero)

ioの出力結果です。

■ GASでの解き方 ■

では、同じ問題をGASで解いてみます。
まず、スプレッドシートにこの様に配置しました。

スプレッドシートの緑のセルに階乗を求める整数の100を入力します。
灰色のセルには100!の計算結果を出力します。
黄色いセルには、100の階乗100!の末尾に0が付く個数を出力します。
0の個数は変数zeroに求めます。

また、factを二次元配列としてfact2に追加して、zeroを二次元配列zero2に追加して、それぞれスプレッドシートに出力します。

※スプレッドシートに表示する場合は、二次元配列としてからの配列に追加をして作成します※

手順はこのようになります。

1:スプレッドシートからアクティブシートをアクセスする

2:階乗を求める整数N(この例の場合は100)を取得する


3:階乗の計算結果factを1で初期化する


4:100×99×98×97・・・4×3×2×1の掛けていく数を格納するmultを宣言する


5:10で割れる回数tenを0で初期化する


6:5で割れる回数fiveを0で初期化する


7:2で割れる回数twoを0で初期化する


8:末尾に付く0の個数zeroを0で初期化する


9:multが10,5,2それぞれで何回割れるのか数えて変数countに格納するので0で初期化する


10:multを代入する変数tempを宣言する

11:forループで100!を計算する

12:階乗の計算に用いたmultをtempに代入してwhileループに入る

13:10,5,2のいずれかで割れる間にtempを割っていってcountとten,five,twoをインクリメントさせる

14:10,5,2それぞれの割れた回数をログ出力

15:2,5で割れた回数が少ない方と10で割れた回数を合計してzeroに格納する

16:0が付く個数をログ表示

17:factをスプレッドシートに表示する二次元配列fact2を宣言する

18:fact2にfactを二次元配列になるように追加する

19:zeroをスプレッドシートに表示する二次元配列zero2を宣言する

20:zero2にzeroを二次元配列になるように追加する

21:スプレッドシートに出力前のfact2とzero2をログ出力して確認する

22:スプレッドシートの灰色の所に100!と、黄色い所に0の個数をそれぞれ二次元配列として出力する

手順1: スプレッドシートからアクティブシートをアクセスする

const ss=SpreadsheetApp.getActiveSheet();

ここで定数ssにSpreadsheetAppから階層を辿ってアクティブシートにアクセスしています。

手順2:階乗を求める整数N(この例の場合は100)を取得する

const N=ss.getRange(1,2).getValue();

手順3:階乗の計算結果factを1で初期化する

let fact=1;

手順4:100×99×98×97・・・4×3×2×1の掛けていく数を格納するmultを宣言する

let mult;

手順5:10で割れる回数tenを0で初期化する

let ten=0;

手順6:5で割れる回数fiveを0で初期化する

let five=0;

手順7:2で割れる回数twoを0で初期化する

let two=0;

手順8:末尾に付く0の個数zeroを0で初期化する

let zero=0;

手順9:multが10,5,2それぞれで何回割れるのか数えて変数countに格納するので0で初期化する

let count;

手順10:multを代入する変数tempを宣言する

let temp;

手順11から13はループです。
まず、forループで100!を求めます。
100!はとてつもなく大きい数になるので、whileループを使って、末尾の0の数を「掛ける数mult」から求めます。

multの値が変わらないように、multをtempに代入して、10または5または2で割れる間割り算をして行き、それぞれの割れる回数ten,five,twoをインクリメントさせます。

手順11:forループで100!を計算する
手順12:階乗の計算に用いたmultをtempに代入してwhileループに入る
手順13:10,5,2のいずれかで割れる間にtempを割っていってcountとten,five,twoをインクリメントさせる

下の図は、fact=1にまず初めに100を掛ける所です。
forループで階乗の計算をしながら、multを使って10で何回割れるのか求める為に、変数tempを利用しています。

この、for,while部分のコードです。

console.log('<<<forループに入る>>>');

  //forループで100!を計算する
  //階乗の計算に用いたmultをtempに代入してwhileループに入る
  //10,5,2のいずれかで割れる間にtempを割っていってcountとten,five,twoをインクリメントさせる
  for (let i = 0; i < N; i++) {
    console.log(`計算前のfact:${fact}`);
    count = 0;
    mult = N - i;
    console.log(`mult=(N-i):【${mult}】`);

    console.log(`fact:${fact}*「${mult}」を計算`);
    fact *= mult;
    console.log(`計算後のfact:【${fact}】`);

    temp = mult;

    //10,5,2のいずれかで割れる間にtempを割っていってcountとten,five,twoをインクリメントさせる
    while (temp % 10 == 0 || temp % 5 == 0 || temp % 2 == 0) {

      console.log('<<<whileループに入りました。>>>');

      if (temp % 10 == 0) {
        temp /= 10
        count++;
        ten++;
        console.log(`mult:${mult}の時、10で${count}回割れました。`);
      } else if (temp % 5 == 0) {
        temp /= 5
        count++;
        five++;
        console.log(`mult:${mult}の時、5で${count}回割れました。`);
      } else if (temp % 2 == 0) {
        temp /= 2
        count++;
        two++;
        console.log(`mult:${mult}の時、2で${count}回割れました。`);
      }

      console.log('<<<whileループを抜けました。>>>');

    }

    console.log(`現在の計算結果fact:${fact}`);
    console.log('----------------------------');

  }

  console.log('<<<forループを抜けました。>>>');

手順14:10,5,2それぞれの割れた回数をログ出力

//10,5,2それぞれの割れた回数をログ出力
  console.log(`multが10で割れた回数:${ten}回`);
  console.log(`multが5で割れた回数:${five}回`);
  console.log(`multが2で割れた回数:${two}回`);

手順15:2,5で割れた回数が少ない方(two または five)と10で割れた回数(ten)を合計してzeroに格納する。階乗の末尾に何個0が付くかは、「10で割れた回数」と「2×5で割れた回数」の合計になります。
なので、2×5のペアを作るため、twoとfiveの少ない方をtenに足した回数がzeroになります。

//2,5で割れた回数が少ない方と10で割れた回数を合計してzeroに格納する
  if (two < five) {
    zero = ten + two
    console.log(`5で割れた回数よりも2で割れた回数の方が少ないので、\n0が付く個数はzero=ten:${ten}+two:${two}=${zero}です。`);
  } else {
    zero = ten + five;
    console.log(`2で割れた回数よりも5で割れた回数の方が少ないので、\n0が付く個数はzero=ten:${ten}+five:${five}=${zero}です。`);
  }

手順16:0が付く個数をログ表示

console.log(`0は${zero}個付きます。`);

手順17:factをスプレッドシートに表示する二次元配列fact2を宣言する

let fact2=[];

手順18:fact2にfactを二次元配列になるように追加する

fact2.push([fact]);

手順19:zeroをスプレッドシートに表示する二次元配列zero2を宣言する

let zero2=[];

手順20:zero2にzeroを二次元配列になるように追加する

zero2.push([zero]);

手順21:スプレッドシートに出力前のfact2とzero2をログ出力して確認する

console.log(fact2);
console.log(zero2);

手順22:スプレッドシートの灰色の所に100!と、黄色い所に0の個数をそれぞれ二次元配列として出力する

ss.getRange(2,2).setValue(fact);
ss.getRange(3,2).setValue(zero2);

実行後のスプレッドシートです。

GASでの全コードはこちらになります。

function loop2no15() {

  //スプレッドシートからアクティブシートをアクセスする
  const ss = SpreadsheetApp.getActiveSheet();

  //階乗を求める整数N(この例の場合は100)を取得する
  const N = ss.getRange(1, 2).getValue();

  //階乗の計算結果factを1で初期化する
  let fact = 1;

  //100×99×98×97・・・4×3×2×1の掛けていく数を格納するmultを宣言する
  let mult;

  //10で割れる回数tenを0で初期化する
  let ten = 0;

  //5で割れる回数fiveを0で初期化する
  let five = 0;

  //2で割れる回数twoを0で初期化する
  let two = 0;

  //末尾に付く0の個数zeroを0で初期化する
  let zero = 0;

  //multが10,5,2それぞれで何回割れるのか数えて変数countに格納するので0で初期化する
  let count;

  //multを代入する変数tempを宣言する
  let temp;

  console.log('<<<forループに入る>>>');

  //forループで100!を計算する
  //階乗の計算に用いたmultをtempに代入してwhileループに入る
  //10,5,2のいずれかで割れる間にtempを割っていってcountとten,five,twoをインクリメントさせる
  for (let i = 0; i < N; i++) {
    console.log(`計算前のfact:${fact}`);
    count = 0;
    mult = N - i;
    console.log(`mult=(N-i):【${mult}】`);

    console.log(`fact:${fact}*「${mult}」を計算`);
    fact *= mult;
    console.log(`計算後のfact:【${fact}】`);

    temp = mult;

    //10,5,2のいずれかで割れる間にtempを割っていってcountとten,five,twoをインクリメントさせる
    while (temp % 10 == 0 || temp % 5 == 0 || temp % 2 == 0) {

      console.log('<<<whileループに入りました。>>>');

      if (temp % 10 == 0) {
        temp /= 10
        count++;
        ten++;
        console.log(`mult:${mult}の時、10で${count}回割れました。`);
      } else if (temp % 5 == 0) {
        temp /= 5
        count++;
        five++;
        console.log(`mult:${mult}の時、5で${count}回割れました。`);
      } else if (temp % 2 == 0) {
        temp /= 2
        count++;
        two++;
        console.log(`mult:${mult}の時、2で${count}回割れました。`);
      }

      console.log('<<<whileループを抜けました。>>>');

    }

    console.log(`現在の計算結果fact:${fact}`);
    console.log('----------------------------');

  }

  console.log('<<<forループを抜けました。>>>');

  //10,5,2それぞれの割れた回数をログ出力
  console.log(`multが10で割れた回数:${ten}回`);
  console.log(`multが5で割れた回数:${five}回`);
  console.log(`multが2で割れた回数:${two}回`);

  //2,5で割れた回数が少ない方と10で割れた回数を合計してzeroに格納する
  if (two < five) {
    zero = ten + two
    console.log(`5で割れた回数よりも2で割れた回数の方が少ないので、\n0が付く個数はzero=ten:${ten}+two:${two}=${zero}です。`);
  } else {
    zero = ten + five;
    console.log(`2で割れた回数よりも5で割れた回数の方が少ないので、\n0が付く個数はzero=ten:${ten}+five:${five}=${zero}です。`);
  }

  //0が付く個数をログ表示
  console.log(`0は${zero}個付きます。`);

  //factをスプレッドシートに表示する二次元配列fact2を宣言する
  let fact2 = [];

  //fact2にfactを二次元配列になるように追加する
  fact2.push([fact]);

  //zeroをスプレッドシートに表示する二次元配列zero2を宣言する
  let zero2 = [];

  //zero2にzeroを二次元配列になるように追加する
  zero2.push([zero]);


  //スプレッドシートに出力前のfact2とzero2をログ出力して確認する
  console.log(fact2);
  console.log(zero2);


  //スプレッドシートの灰色の所に100!と、黄色い所に0の個数をそれぞれ二次元配列として出力する
  ss.getRange(2, 2).setValue(fact);
  ss.getRange(3, 2).setValue(zero2);


}

宜しかったらコピペしてアレンジして見て下さい。
お疲れ様でした、ブレイクタイムフォトはこちらになります。

代々木公園で撮影した紫陽花

■ 参考文献の紹介■

じっくり丁寧にPythonを学びたい方向け。
まずはpaizaラーニングなどの学習コンテンツで学んで、基礎をマスターしたら、この本でじっくりと初級から中級レベルを目指せます。

初めてGASを学ぶ方向け。
スプレッドシートの基本的な使い方からGASのベースとなるJavaScriptの基礎文法、GASでの初歩的なプログラミングを学べます。

GASに少し慣れて来たら、基礎固めとリファレンスとしてこの本でじっくり学べます。

サイトマップはこちらから

paizaレベルアップ問題集でPythonとGASを解いて見たに戻る
メインメニューに戻る
Python自作サンプル
GASサンプル
基本情報技術者試験

←前の問題へ          次の問題へ→