ספרות בעשרות

הנה סיפור עם מוסר השכל יפה, לפחות מבחינתי:

לימדתי שיעור על לולאות, ונתתי לסטודנטים שאלה עליכם לכתוב שיטה שחתימתה

public int digitsNum(int n)

השיטה תקבל כפרמטר מספר שלם n ותחזיר את מספר הספרות במספר. למשל, עבור המספר 245 השיטה תחזיר 3, ועבור המספר 87345 השיטה תחזיר 5.

אם אתם לא מכירים את הרעיון, עצרו רגע לחשוב עליו. הרעיון הקלאסי הוא “לקלף” את הספרות מהמספר, ספרה אחרי ספרה, ולספור תוך כדי את הספרות. כאשר מגיעים לאפס זה אומר שלא נשארו יותר ספרות, ספרנו את כולן. האמת שזה גם תרגיל טוב בפעולת החלוקה בשלמים חלוקת מספר שלם ב-10 תשאיר את המספר בלי ספרת האחדות למשל:

245 / 10 = 24.5 –> 24

כיוון שמדובר במספר שלם, המספר עובר “קטיעה” כל הספרות מימין לנקודה העשרונית נמחקות ונשאר רק החלק השלם. במקרה של חלוקה בעשר זה פשוט המספר בלי ספרת האחדות.

אז הנה מימוש השיטה כפי שהראיתי והסברתי אינסוף פעמים במהלך הקריירה שלי

public int digitsNum(int n) {

    int count = 0;

    while(n > 0) {

         count++;

         n /= 10;

    }

    return count;

}

פשוט.

אגב, הפתרון הזה מכיל באג קטן, אתם מוזמנים למצוא אותו.

נתתי לסטודנטים זמן למצוא את הפתרון ואז ביקשתי מהם רעיונות איך לעשות את זה. הסטודנטים הצביעו בנימוס, ונתתי את רשות הדיבור לאחד מהם תלמיד תיכון צעיר מאוד. הוא התחיל לתאר את הפתרון שלו, אבל לא לגמרי הבנתי אותו, הפתרון שלו היה שונה מאוד משלי וכמעט שהתפתיתי לפסול אותו כלא נכון. למזלו (ולמזלי!) סטודנט אחר הבין מה הוא אומר ו”פירש” אותו בכמה מילים ברורות. מיד הבנתי את הרעיון של הסטודנט ובבת אחת גם הבנתי שאני עד לאחד הרגעים הנדירים האלו רגע שבו מצאתי פתאום דרך חדשה לבעיה שאני מכיר כל כך טוב, דרך יפה ויצירתית ומעניינת.

אז מה הפתרון? הרעיון שעומד בבסיסו אומר שכל המספרים בני ספרה אחת הם קטנים מ-10.

כל המספרים בני שתי ספרות קטנים מ-100 (וגדולים מעשר כמובן).

כל המספרים בני שלוש ספרות קטנים מ-1000 וכן הלאה.

איך זה קשור? נגדיר משתנה שישמור את הגבול של המספרים בני x ספרות. למשל, בהתחלה המשתנה הזה יהיה שווה ל-10. אם המספר שלנו קטן מהמשתנה, זה אומר שהוא מכיל ספרה אחת. אם לא, נכפיל את המשתנה ב-10 ונקבל 100, שזה הגבול של המספרים בני שתי ספרות. אם המספר שלנו קטן מזה, סימן שהוא בן שתי ספרות. אם לא, נכפיל בעשר, וכן הלאה. הנה הקוד:

public int digitsNum(int n) {

     int biggest = 10, count = 1;

     while(n >= biggest) {

           biggest *= 10;

            count++;

    }

    return count;

}

והפתרון הזה גם פותר את הבאג מהפתרון שלי.

למה אהבתי את הפתרון? אני מניח שהסיבה העיקרית היא כי הוא הראה לי דרך חדשה שלא הכרתי לפתור בעיה מוכרת. בעיה שכבר פתרתי עשרות פעמים וכבר חשבתי שאין מה לחדש בה. והנה התבדיתי ראיתי פתרון יצירתי ויפה שפותר אותה בעיה בדרך אחרת.

אז מה למדנו מהעניין? לדעתי, לקח חשוב יצירתיות היא תכונה חשובה והיא המנוע שמניע אותנו. החיפוש אחרי פתרונות יפים יותר, אלגנטים יותר או פשוט “אחרים”,  הוא לדעתי מה שמניע את הקדמה, ואולי זה נשמע קצת פומפוזי, אבל בסופו של דבר, בלי פתרונות שכאלה כנראה שלא היינו מתקדמים לשום מקום…

ושאלה לאוהבי החידות והאתגרים תוכלו לחשוב על עוד דרך יצירתית לחשב את מספר הספרות במספר?