בגרות במדעי המחשב יסודות מדעי המחשב 899371 - קיץ 2026
1–2 יח"ל · שאלון 899371 · 6 שאלות · 2:30 שעות · פתרון מלא לכל סעיף
בחינת הבגרות במדעי המחשב, יסודות מדעי המחשב, קיץ 2026, כל 6 השאלות כמו בשאלון. לכל סעיף יש תשובה ופתרון מלא: הרעיון, הקוד או המעקב, ובדיקה קצרה. כל קוד מופיע ב-Java וב-C#. נסו לפתור לבד, ואז פתחו את הפתרון.
הוראות הבחינה (כמו בשאלון)
א. משך הבחינה: שעתיים וחצי.
ב. מבנה השאלון ומפתח ההערכה: בשאלון זה שני פרקים.
פרק ראשון – (20×2) – 40 נקודות
פרק שני – (30×2) – 60 נקודות
סך הכול – 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנוּת.
ד. הוראה מיוחדת:
את כל התוכניות שיש לכתוב בשפת מחשב כתבו בשפה אחת בלבד – Java או C#.
הערה: לא יורדו נקודות אם תכתבו בתוכניות אות גדולה במקום אות קטנה או להפך.
יש לכתוב במחברת הבחינה בלבד. יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
השאלות
בשאלון זה שני פרקים.
יש לענות על שאלות משני הפרקים, לפי ההוראות בכל פרק.
הערה: בכל שאלה שנדרשת בה קליטה, אין צורך לבדוק את תקינות הקלט.
לפותרים בשפת Java: בכל שאלה שנדרשת בה קליטה, הניחו שבתוכנית כתובה ההוראה:
Scanner scan = new Scanner (System.in);
הערה: בקיץ תשפ"ו (2026) שונו כללי המענה בשאלון זה (על פי הודעת משרד החינוך "ההנחיות החדשות למענה על שאלות הבחינה", מדעי המחשב 899371, קיץ תשפ"ו): יש לענות על 4 שאלות מתוך 6 השאלות במבחן. לכל שאלה – 25 נקודות. סך הכול: 100 נקודות. בבחינה יש שאלה אחת בלבד בנושא מחלקה מורכבת (מחלקה שאחת מתכונותיה היא אובייקט של מחלקה אחרת).
פרק ראשון
ענו על שתיים מן השאלות 1–3 (לכל שאלה – 20 נקודות).
שאלה 1 · מעקב – חיסור ריבועים שלמים (20 נקודות)
לפניכם קטע תוכנית, הכתוב בשפות Java ו־ C#.
Java
int n = 23;
int steps = 0;
while (n > 0) {
int root = (int)(Math.sqrt(n));
int square = (int)(Math.pow(root, 2));
n = n - square;
steps ++;
}
System.out.println(steps);C#
int n = 23;
int steps = 0;
while (n > 0) {
int root = (int)(Math.Sqrt(n));
int square = (int)(Math.Pow(root, 2));
n = n - square;
steps ++;
}
Console.WriteLine(steps);עקבו בעזרת טבלת מעקב אחרי ביצוע קטע התוכנית, וכתבו את המספר שקטע התוכנית מדפיס.
בטבלת המעקב יש לכלול עמודה בעבור כל אחד מן המשתנים האלה: n , steps , root , square .
כתבו דוגמה למספר הגדול מ־ 1 שמוצב ב־ n (בתחילת הקטע) שבעבורו קטע התוכנית מדפיס 1 (אין צורך להציג מעקב).
◂ פתרון מלא לשאלה 1
סעיף א
5
מה נדרש: לעקוב אחרי ביצוע הקטע (עמודות n, steps, root, square) ולכתוב מה יודפס.
רעיון: בכל סיבוב מחשבים את השורש השלם של n (החלק השלם של √n), מעלים אותו בריבוע ומקבלים את הריבוע השלם הגדול ביותר שאינו גדול מ־ n. מחסירים אותו מ־ n וסופרים צעד. הלולאה נעצרת כאשר n מגיע ל־ 0.
פתרון – טבלת מעקב:
| n | root | square | steps | הערה |
|---|---|---|---|---|
| 23 | – | – | 0 | ערכים התחלתיים, 23 > 0 – נכנסים ללולאה |
| 7 | 4 | 16 | 1 | √23 ≈ 4.79 → 4, 4² = 16, 23 − 16 = 7 |
| 3 | 2 | 4 | 2 | √7 ≈ 2.65 → 2, 2² = 4, 7 − 4 = 3 |
| 2 | 1 | 1 | 3 | √3 ≈ 1.73 → 1, 1² = 1, 3 − 1 = 2 |
| 1 | 1 | 1 | 4 | √2 ≈ 1.41 → 1, 2 − 1 = 1 |
| 0 | 1 | 1 | 5 | √1 = 1, 1 − 1 = 0, התנאי n > 0 לא מתקיים – יציאה |
הקטע מדפיס: 5
בדיקה: הפלט של הקטע הוא 5. (בשאלון מודפס בשורה n = n – square סימן מינוס טיפוגרפי; בתמלול נכתב מינוס רגיל -, כפי שכותבים בקוד.)
טעות נפוצה: לחשוב ש־ (int)(Math.sqrt(n)) מעגל לשלם הקרוב (למשל √23 ≈ 4.79 ל־ 5). ההמרה ל־ int קוטעת את החלק העשרוני, לכן מתקבל 4.
סעיף ב
למשל n = 4 (כל ריבוע שלם גדול מ־ 1: 4, 9, 16, ...)
מה נדרש: ערך התחלתי של n, גדול מ־ 1, שבעבורו הקטע מדפיס 1.
רעיון: הקטע מדפיס 1 רק אם הלולאה מתבצעת פעם אחת בדיוק, כלומר כבר בסיבוב הראשון n − square = 0. זה קורה כאשר n שווה בדיוק לריבוע של השורש השלם שלו – כלומר n הוא ריבוע שלם.
פתרון: למשל n = 4: root = 2, square = 4, n = 4 − 4 = 0, steps = 1 – יודפס 1.
(כל ריבוע שלם גדול מ־ 1 מתאים: 4, 9, 16, 25, ...)
בדיקה: על כל הערכים 2–100, הערכים שבעבורם מודפס 1 הם בדיוק 4, 9, 16, 25, 36, 49, 64, 81, 100.
שאלה 2 · מהירויות נסיעה וקנסות (20 נקודות)
הפרמטר max הוא מספר שלם חיובי המייצג את מהירות הנסיעה המקסימלית בקמ"ש המותרת לכלי רכב בקטע כביש מסוים.
הפרמטר min הוא מספר שלם חיובי המייצג את מהירות הנסיעה המינימלית בקמ"ש המותרת לכלי רכב באותו קטע כביש.
כתבו פעולה חיצונית ששמה getStatus בשפת Java או GetStatus בשפת C# המקבלת מספר שלם חיובי – speed , המייצג את מהירות הנסיעה בקמ"ש של כלי רכב כלשהו באותו קטע כביש, ואת הפרמטרים max ו־ min .
הפעולה תחזיר מספר שלם על פי התנאים האלה:
– אם מהירות הנסיעה של כלי הרכב גבוהה ב־ 10 קמ"ש לפחות ממהירות הנסיעה המקסימלית המותרת, הפעולה תחזיר 1 .
– אם מהירות הנסיעה של כלי הרכב נמוכה ב־ 10 קמ"ש לפחות ממהירות הנסיעה המינימלית המותרת, הפעולה תחזיר -1 .
– אם שני התנאים שלעיל אינם מתקיימים, הפעולה תחזיר 0 .
המערך speeds הוא מערך מטיפוס שלם המכיל מידע על מהירויות הנסיעה של כלי רכב שונים באותו קטע כביש מסוים (כל תא במערך מציג את מהירות הנסיעה של כלי רכב אחר). המערך אינו מסודר בסדר מסוים.
כתבו פעולה חיצונית ששמה getAllStatus בשפת Java או GetAllStatus בשפת C# המקבלת את המערך speeds ואת הפרמטרים max ו־ min .
הפעולה תחזיר מערך חדש מטיפוס שלם בגודל זהה למערך speeds , המציג בכל תא את המספר 1 או -1 או 0 בהתאם לכלי הרכב שנמצא באותו האינדקס במערך speeds (על פי התנאים בסעיף א).
דוגמה: בעבור max = 70 , min = 30 , והמערך speeds :
| אינדקס | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| speeds | 80 | 50 | 79 | 90 | 20 | 100 | 25 |
יוחזר המערך שלהלן:
| אינדקס | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 1 | -1 | 1 | 0 |
הערות: – יש להשתמש בפעולה שכתבתם בסעיף א.
– אין לשנות את המערך speeds .
כלי רכב יקבל קנס אם מהירות הנסיעה שלו בקטע כביש זה גבוהה ב־ 10 קמ"ש לפחות מן המהירות המקסימלית המותרת, או נמוכה ב־ 10 קמ"ש לפחות מן המהירות המינימלית המותרת.
כתבו פעולה חיצונית ששמה mostFined בשפת Java או MostFined בשפת C# , המקבלת את המערך speeds ואת הפרמטרים max ו־ min .
הפעולה תחזיר true אם לפחות חצי מכמות כלי הרכב במערך speeds קיבלו קנס, אחרת הפעולה תחזיר false .
דוגמה: בעבור המערך הנתון בסעיף ב הפעולה תחזיר true , כי מבין שבעת כלי הרכב במערך, ארבעה מקבלים קנס (כלי הרכב באינדקסים 0 , 3 , 4 , 5).
הערה: יש להשתמש בפעולה שכתבתם בסעיף ב.
◂ פתרון מלא לשאלה 2
סעיף א
speed ≥ max + 10 → 1 ; speed ≤ min − 10 → -1 ; אחרת 0
מה נדרש: פעולה המסווגת מהירות אחת: 1 (מהירה מדי), -1 (איטית מדי) או 0.
רעיון: "גבוהה ב־ 10 לפחות מ־ max" פירושו speed − max ≥ 10, כלומר speed ≥ max + 10. באותו אופן "נמוכה ב־ 10 לפחות מ־ min" פירושו speed ≤ min − 10. בודקים את שני התנאים, ואם אף אחד אינו מתקיים מחזירים 0.
פתרון: הקוד המלא – בלשונית Java / C#.
if (speed >= max + 10) return 1;
if (speed <= min - 10) return -1;
return 0;בדיקה: max = 70, min = 30: עבור 80 → 1 (80 ≥ 80), עבור 79 → 0, עבור 20 → -1 (20 ≤ 20), עבור 21 → 0.
טעות נפוצה: לכתוב > במקום ≥ – אז מהירות 80 (גבוהה ב־ 10 בדיוק) לא תקבל 1, בניגוד לדוגמה בסעיף ב.
public static int getStatus(int speed, int max, int min)
{
if (speed >= max + 10)
return 1;
if (speed <= min - 10)
return -1;
return 0;
}סעיף ב
result[i] = getStatus(speeds[i], max, min) לכל i במערך חדש
מה נדרש: מערך חדש באותו גודל, שבו כל תא הוא תוצאת getStatus על התא המתאים ב־ speeds.
רעיון: יוצרים מערך result בגודל speeds.length, ועוברים בלולאה על כל האינדקסים: result[i] = getStatus(speeds[i], max, min). המערך speeds רק נקרא – לא משנים אותו.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: על המערך מהדוגמה (max = 70, min = 30) התקבל [1, 0, 0, 1, -1, 1, 0], כמו בשאלה, והמערך speeds נשאר [80, 50, 79, 90, 20, 100, 25].
public static int[] getAllStatus(int[] speeds, int max, int min)
{
int[] result = new int[speeds.length];
for (int i = 0; i < speeds.length; i++)
{
result[i] = getStatus(speeds[i], max, min);
}
return result;
}סעיף ג
סופרים תאים ≠ 0 במערך מ־ getAllStatus ומחזירים count * 2 >= speeds.length
מה נדרש: להחזיר true אם לפחות חצי מכלי הרכב קיבלו קנס.
רעיון: כלי רכב מקבל קנס בדיוק כאשר הסטטוס שלו שונה מ־ 0 (1 או -1). מפעילים את getAllStatus, סופרים את התאים השונים מ־ 0, ובודקים "לפחות חצי": count * 2 >= speeds.length (כך נמנעים מחילוק שלמים – למשל ב־ 7 כלי רכב, 7 / 2 = 3 בחילוק שלמים).
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: בדוגמה 4 קנסות מתוך 7: 4·2 = 8 ≥ 7 → true. נבדק גם 2 מתוך 4 → true ו־ 1 מתוך 3 → false.
טעות נפוצה: לבדוק count >= speeds.length / 2 – בחילוק שלמים 7 / 2 = 3, ואז 3 קנסות מתוך 7 (פחות מחצי) יחזירו true בטעות.
public static boolean mostFined(int[] speeds, int max, int min)
{
int[] status = getAllStatus(speeds, max, min);
int count = 0;
for (int i = 0; i < status.length; i++)
{
if (status[i] != 0)
count++;
}
return count * 2 >= speeds.length;
}שאלה 3 · בול פגיעה – מחרוזות (20 נקודות)
במשחק "בול פגיעה" בוחרים מראש מחרוזת סודית, המורכבת מן האותיות Z–A ללא סדר כלשהו. כל אות יכולה להופיע במחרוזת הסודית פעם אחת לכל היותר (כך שאורך המחרוזת הוא בין 1 ל־ 26).
המשחק מתנהל באופן שלהלן:
השחקן מנחש מחרוזת מסוימת (שהוא חושב שהיא המחרוזת הסודית). בעבור כל אות במחרוזת הניחוש, הוא מקבל ציון לפי מידת ההצלחה של הניחוש שלו:
– ציון "בול" ניתן בעבור ניחוש נכון של האות ושל המקום שלה במחרוזת הסודית.
– ציון "פגיעה" ניתן בעבור ניחוש נכון של האות במחרוזת הסודית אך במקום הלא נכון.
– ציון "החמצה" ניתן בעבור ניחוש של אות שאינה קיימת כלל במחרוזת הסודית.

ציון "בול" אחד בעבור ניחוש נכון של האות G ושל המקום שלה במחרוזת הסודית (באינדקס 1).
שני ציוני "פגיעה" בעבור ניחוש נכון של האותיות A ו־ F במחרוזת הסודית אך במקומות הלא נכונים.
ציון "החמצה" אחד בעבור ניחוש לא נכון של האות C , שאינה קיימת כלל במחרוזת הסודית.
כתבו פעולה חיצונית ששמה guess בשפת Java או Guess בשפת C# , המקבלת שני פרמטרים:
מחרוזת סודית – secretStr , ומחרוזת ניחוש – playerStr .
הניחו ששתי המחרוזות תקינות (כלומר מופיעות בהן רק האותיות Z–A וכל אות מופיעה בכל מחרוזת פעם אחת לכל היותר).
אם האורך של מחרוזת הניחוש שונה משל המחרוזת הסודית, הפעולה תדפיס הודעת שגיאה "Size Error" .
אם האורך של מחרוזת הניחוש זהה לאורך של המחרוזת הסודית, הפעולה תדפיס את מספר ציוני ה"בול", מספר ציוני ה"פגיעה" ומספר ציוני ה"החמצה" בעבור הניחוש של השחקן (כל הדפסה בשורה חדשה).
◂ פתרון מלא לשאלה 3
פתרון
לכל i: place = secretStr.indexOf(playerStr.charAt(i)); place == i → בול, place != -1 → פגיעה, אחרת החמצה. בדוגמה: 1, 2, 1
מה נדרש: פעולה המדפיסה "Size Error" אם האורכים שונים, ואחרת את מספר ה"בול", ה"פגיעה" וה"החמצה" – כל אחד בשורה.
רעיון: עוברים על כל אות c = playerStr.charAt(i) בניחוש ומחפשים אותה במחרוזת הסודית עם indexOf:
כיוון שכל אות מופיעה במחרוזת הסודית פעם אחת לכל היותר, indexOf מחזיר את המקום היחיד שלה, ולכן הבדיקה place == i מספיקה.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה:
| סודית | ניחוש | פלט |
|---|---|---|
| FGAV | AGCF | 1, 2, 1 (כמו בדוגמה) |
| ABCD | ABC | Size Error |
| ABCD | ABCD | 4, 0, 0 |
| ABCD | DCBA | 0, 4, 0 |
| ABCD | XYZW | 0, 0, 4 |
טעות נפוצה: לספור "פגיעה" גם לאות שהיא "בול" (למשל לבדוק קודם indexOf != -1). צריך לבדוק קודם את ה"בול" ורק אחר כך את ה"פגיעה".
public static void guess(String secretStr, String playerStr)
{
if (playerStr.length() != secretStr.length())
{
System.out.println("Size Error");
}
else
{
int bul = 0, hit = 0, miss = 0;
for (int i = 0; i < playerStr.length(); i++)
{
char c = playerStr.charAt(i);
int place = secretStr.indexOf(c);
if (place == i)
bul++;
else if (place != -1)
hit++;
else
miss++;
}
System.out.println(bul);
System.out.println(hit);
System.out.println(miss);
}
}פרק שני
ענו על שתיים מן השאלות 4–6 (לכל שאלה – 30 נקודות).
שאלה 4 · המחלקה Order – הזמנות ומשלוחים (30 נקודות)
נתונה המחלקה Order , המייצגת פרטי הזמנה של מוצר כלשהו, ולה ארבע תכונות:
לקוח שהזמין משלוח עד הבית צריך לשלם תוספת של 100 ש"ח. אם הוזמנו 10 יחידות לפחות באותה הזמנה, ונוסף על כך סכום ההזמנה (לא כולל המשלוח) גבוה מ־ 170.00 ש"ח – המשלוח ניתן חינם.
הניחו שקיימות פעולות get/Get ו־ set/Set לתכונות המחלקה.
כתבו במחלקה Order פעולה בונה המקבלת את הקוד המזהה של המוצר – productID ואת מחיר המוצר – price .
הפעולה תאתחל את תכונות המחלקה כך שתתקבל הזמנה של המוצר – productID , במחיר של המוצר – price , בכמות של יחידה אחת, עם משלוח עד הבית.
כתבו במחלקה Order פעולה פנימית ששמה totalPrice בשפת Java או TotalPrice בשפת C# , המחזירה מספר ממשי של הסכום הכולל לתשלום של כל הפריטים בהזמנה ללא דמי משלוח.
כתבו במחלקה Order פעולה פנימית ששמה totalCost בשפת Java או TotalCost בשפת C# , המחזירה מספר ממשי של הסכום כולל דמי משלוח שהלקוח צריך לשלם (אם ההזמנה לא כוללת משלוח עד הבית או המשלוח חינם, יוחזר סכום ההזמנה ללא דמי משלוח).
הערה: יש להשתמש בפעולה שכתבתם בתת־סעיף ב(1).
נתון מערך – allOrders מטיפוס Order המכיל הזמנות שבוצעו בשבוע מסוים. המערך אינו מסודר לפי סדר כלשהו ואין בו ערכי null .
כתבו פעולה חיצונית ששמה sumQuantity בשפת Java או SumQuantity בשפת C# , המקבלת את המערך allOrders . הפעולה מחזירה מערך חדש מטיפוס שלם בגודל 100 , שבכל תא מופיעה כמות היחידות הכוללת שהוזמנה מן המוצר, שהקוד המזהה שלו זהה לאינדקס של התא.
למשל, אם הוזמנו ממוצר שהקוד המזהה שלו הוא 0 – בהזמנה אחת 15 יחידות, בהזמנה אחרת 20 יחידות, ובהזמנה נוספת 3 יחידות – יופיע בתא של אינדקס 0 המספר 38 .
◂ פתרון מלא לשאלה 4
סעיף א
productID ו־ price מהפרמטרים, quantity = 1, delivery = true
מה נדרש: פעולה בונה Order(productID, price) שיוצרת הזמנה של יחידה אחת עם משלוח.
רעיון: את productID ו־ price מעתיקים מהפרמטרים; quantity מקבלת 1 ו־ delivery מקבלת true. (בקוד מוצגות גם הגדרות התכונות של המחלקה.)
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: new Order(5, 20.0) – מתקבלים productID = 5, price = 20.0, quantity = 1, delivery = true.
private int productID;
private double price;
private int quantity;
private boolean delivery;
public Order(int productID, double price)
{
this.productID = productID;
this.price = price;
this.quantity = 1;
this.delivery = true;
}סעיף ב(1)
return price * quantity;
מה נדרש: סכום ההזמנה בלי דמי משלוח.
רעיון: הסכום הוא מחיר ליחידה כפול מספר היחידות: price * quantity (התוצאה ממשית כי price ממשי).
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: הזמנה של יחידה אחת במחיר 20.0 – הוחזר 20.0.
public double totalPrice()
{
return price * quantity;
}סעיף ב(2)
sum = totalPrice(); אם delivery וגם לא (quantity >= 10 וגם sum > 170) – מוסיפים 100
מה נדרש: הסכום לתשלום כולל דמי משלוח (100 ש"ח), אלא אם אין משלוח או שהמשלוח חינם.
רעיון:
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה:
| מחיר | כמות | משלוח | totalCost | הסבר |
|---|---|---|---|---|
| 20.0 | 1 | כן | 120.0 | פחות מ־ 10 יחידות – משלמים 100 |
| 20.0 | 10 | כן | 200.0 | 10 יחידות ו־ 200 > 170 – משלוח חינם |
| 17.0 | 10 | כן | 270.0 | 170 אינו גבוה מ־ 170 – משלמים |
| 30.0 | 9 | כן | 370.0 | 270 > 170 אבל רק 9 יחידות – משלמים |
| 30.0 | 9 | לא | 270.0 | אין משלוח |
טעות נפוצה: לבדוק sum >= 170 – הסכום צריך להיות גבוה מ־ 170.00, לכן 170 בדיוק אינו מזכה במשלוח חינם.
public double totalCost()
{
double sum = totalPrice();
boolean freeDelivery = quantity >= 10 && sum > 170.00;
if (delivery && !freeDelivery)
sum = sum + 100;
return sum;
}סעיף ג
int[100]; לכל הזמנה: sums[getProductID()] += getQuantity()
מה נדרש: מערך מונים בגודל 100 – בתא i סך היחידות שהוזמנו מהמוצר שקודו i.
רעיון: זהו "מערך מונים": הקוד המזהה (0–99) משמש ישירות כאינדקס. יוצרים int[100] (כל התאים מאותחלים ל־ 0), ועוברים פעם אחת על allOrders: לכל הזמנה מוסיפים את getQuantity() לתא שהאינדקס שלו הוא getProductID(). אין צורך בלולאה פנימית.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: הזמנות: (קוד 0, 15), (קוד 7, 4), (קוד 0, 20), (קוד 0, 3), (קוד 99, 2). התקבל מערך בגודל 100 ובו תא 0 = 38 (כמו בדוגמה), תא 7 = 4, תא 99 = 2, ושאר התאים 0.
טעות נפוצה: לפנות ישירות לתכונות של הזמנה אחרת (allOrders[i].quantity) מתוך פעולה חיצונית – התכונות פרטיות, ולכן חייבים להשתמש ב־ getQuantity() ו־ getProductID().
public static int[] sumQuantity(Order[] allOrders)
{
int[] sums = new int[100];
for (int i = 0; i < allOrders.length; i++)
{
int id = allOrders[i].getProductID();
sums[id] = sums[id] + allOrders[i].getQuantity();
}
return sums;
}שאלה 5 · לקוחות ותאריכי לידה – מחלקה מורכבת (30 נקודות)
נתונה המחלקה Birthdate – תאריך לידה, ולה שלוש תכונות:
הניחו שקיימות פעולות get/Get ו־ set/Set לתכונות המחלקה.
כתבו במחלקה Birthdate פעולה פנימית ששמה sameDate בשפת Java או SameDate בשפת C# המקבלת עצם אחר – other מטיפוס Birthdate .
הפעולה מחזירה true אם תאריכי הלידה זהים, אחרת היא מחזירה false .
בחברת ההייטק "רשת חברתית" פיתחו מערכת שמחפשת דמיון בין לקוחות החברה. לשם כך בנתה החברה את המחלקה Client – לקוח, ולה שלוש תכונות:
הניחו שקיימות פעולות get/Get ו־ set/Set לתכונות המחלקה.
ראשי התיבות של שמות שני הלקוחות הם זהים אם גם האות הראשונה בשם הפרטי שלהם זהה וגם האות הראשונה בשם המשפחה שלהם זהה.
כתבו במחלקה Client פעולה פנימית ששמה sameInitials בשפת Java או SameInitials בשפת C# , המקבלת עצם אחר – other מטיפוס Client . הפעולה מחזירה true אם ראשי התיבות של שמות שני הלקוחות זהים. אחרת הפעולה מחזירה false .
במערכת זו, שני לקוחות נחשבים "דומים" אם גם ראשי התיבות של שמותיהם זהים וגם תאריכי הלידה שלהם זהים (אם רק תנאי אחד מתקיים הלקוחות אינם "דומים").
כתבו במחלקה Client פעולה פנימית ששמה areSame בשפת Java או AreSame בשפת C# , המקבלת עצם אחר – other מטיפוס Client . הפעולה מחזירה true אם שני הלקוחות "דומים", אחרת הפעולה מחזירה false .
יש להשתמש בפעולות שכתבתם בסעיף א ובתת־סעיף ב(1).
במערכת זו, לקוח נחשב "ייחודי" אם אין שום לקוח אחר ש"דומה" לו (כפי שהוגדר בתת־סעיף ב(2)).
כתבו פעולה חיצונית ששמה uniques בשפת Java או Uniques בשפת C# המקבלת מערך – clients מטיפוס Client של כל הלקוחות במערכת. המערך אינו מסודר לפי סדר כלשהו ואין בו ערכי null . הפעולה תדפיס את האות הראשונה בשם הפרטי של הלקוחות ה"ייחודיים" במערך (כל הדפסה בשורה חדשה).
יש להשתמש בפעולה שכתבתם בתת־סעיף ב(2).
◂ פתרון מלא לשאלה 5
סעיף א
return day == other.getDay() && month == other.getMonth() && year == other.getYear();
מה נדרש: פעולה פנימית ב־ Birthdate הבודקת אם שני תאריכים זהים.
רעיון: שני תאריכים זהים אם היום, החודש וגם השנה שווים. את התכונות של העצם הנוכחי (this) אפשר לקרוא ישירות; את התכונות של other קוראים בפעולות get (ב־ Java מותר גם other.day מתוך אותה מחלקה, אבל השימוש ב־ get ברור יותר).
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: 5/3/2008 מול 5/3/2008 → true; מול 5/4/2008 → false; מול 5/3/2009 → false.
טעות נפוצה: להשוות את העצמים עצמם (this == other) – זו השוואת הפניות, ולא השוואת התאריכים.
public boolean sameDate(Birthdate other)
{
return this.day == other.getDay() &&
this.month == other.getMonth() &&
this.year == other.getYear();
}סעיף ב(1)
return firstNameInitial == other.getFirstNameInitial() && lastNameInitial == other.getLastNameInitial();
מה נדרש: פעולה פנימית ב־ Client הבודקת אם לשני לקוחות אותה אות ראשונה בשם הפרטי וגם אותה אות ראשונה בשם המשפחה.
רעיון: התכונות הן מטיפוס char, ולכן משווים אותן ישירות עם == ומחברים את שתי ההשוואות ב־ &&.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: לקוחות D.C ו־ D.C → true; D.C ו־ D.K → false.
public boolean sameInitials(Client other)
{
return this.firstNameInitial == other.getFirstNameInitial() &&
this.lastNameInitial == other.getLastNameInitial();
}סעיף ב(2)
return sameInitials(other) && birthdate.sameDate(other.getBirthdate());
מה נדרש: פעולה areSame המחזירה true רק אם ראשי התיבות זהים וגם תאריכי הלידה זהים.
רעיון: זו מחלקה מורכבת – התכונה birthdate היא עצם מטיפוס Birthdate. לכן את השוואת התאריכים מעבירים לפעולה sameDate של העצם birthdate:
this.birthdate.sameDate(other.getBirthdate()), ומחברים עם sameInitials(other) ב־ &&.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: D.C 5/3/2008 מול D.C 5/3/2008 → true; מול D.K 5/3/2008 (ראשי תיבות שונים) → false; מול D.C 5/4/2008 (תאריך שונה) → false.
טעות נפוצה: להשוות this.birthdate == other.getBirthdate() – אלה שני עצמים שונים גם כשהתאריכים זהים, ולכן ההשוואה תחזיר false.
public boolean areSame(Client other)
{
return this.sameInitials(other) &&
this.birthdate.sameDate(other.getBirthdate());
}סעיף ג
לולאה כפולה: לקוח i ייחודי אם אין j ≠ i עם clients[i].areSame(clients[j]); אז מדפיסים את getFirstNameInitial()
מה נדרש: להדפיס את האות הראשונה בשם הפרטי של כל לקוח שאין במערך לקוח אחר הדומה לו.
רעיון: לולאה כפולה. לכל לקוח i עוברים על כל הלקוחות j; אם j ≠ i ו־ clients[i].areSame(clients[j]) – הלקוח i אינו ייחודי ומפסיקים לחפש. אם לא נמצא אף לקוח דומה – מדפיסים את getFirstNameInitial() של לקוח i.
התנאי i != j חשוב: כל לקוח "דומה" לעצמו, ובלעדיו אף לקוח לא היה ייחודי.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: מערך של 6 לקוחות: a = D.C 5/3/2008, b = D.C 5/3/2008, c = D.K 5/3/2008, e = E.C 5/4/2008, f = R.L 5/4/2008, g = D.C 5/4/2008. הלקוחות a ו־ b דומים זה לזה, ולכן אינם ייחודיים. מודפסים (כל אחד בשורה): D (של c), E, R, D (של g).
טעות נפוצה: להתחיל את הלולאה הפנימית מ־ j = i + 1 – כך לא בודקים את הלקוחות שלפני i, ולקוח שדומה ללקוח קודם יודפס בטעות כייחודי.
public static void uniques(Client[] clients)
{
for (int i = 0; i < clients.length; i++)
{
boolean unique = true;
for (int j = 0; j < clients.length && unique; j++)
{
if (i != j && clients[i].areSame(clients[j]))
unique = false;
}
if (unique)
System.out.println(clients[i].getFirstNameInitial());
}
}שאלה 6 · ספרות משמאל ומימין – מספר קפרקר מאוזן (30 נקודות)
undefined
ממשו את הפעולה שלפניכם:
Java – public static int leftDigits (int num, int k)
C# – public static int LeftDigits (int num, int k)
num הוא מספר חיובי, ו־ k הוא מספר חיובי, הקטן מכמות הספרות של num (כלומר אורך המספר num).
הפעולה תחזיר את המספר המיוצג על ידי k הספרות שמצד שמאל של המספר num .
דוגמה: עבור k = 5 ו־ num = 260043100 , הפעולה תחזיר את המספר 26004 .
ממשו את הפעולה שלפניכם:
Java – public static int rightDigits (int num, int k)
C# – public static int RightDigits (int num, int k)
num הוא מספר חיובי, ו־ k הוא מספר חיובי, הקטן מכמות הספרות של num (כלומר אורך המספר num).
הפעולה תחזיר את המספר המיוצג על ידי k הספרות שמצד ימין של המספר num (הניחו שהמספר המוחזר תקין ואינו מתחיל ב־ 0).
דוגמה: עבור k = 5 ו־ num = 260043100 , הפעולה תחזיר את המספר 43100 .
מספר שלם חיובי נקרא "קפרקר מאוזן" כאשר הוא מקיים את התנאי שלהלן:
מעלים את המספר בריבוע, את התוצאה מפצלים באמצע לשני חלקים שווים באורכם (כלומר מספר הספרות בתוצאה הוא זוגי, וכמות הספרות בכל חלק זהה), וסכום שני החלקים שווה למספר המקורי.
שתי דוגמאות: המספרים 9 ו־ 4950 הם "קפרקר מאוזן".
הסבר:
| המספר | העלאה בריבוע | החלק הימני | החלק השמאלי | סכום |
|---|---|---|---|---|
| 9 | 9² = 81 | 1 | 8 | 8 + 1 = 9 |
| 4950 | 4950² = 24502500 | 2500 | 2450 | 2450 + 2500 = 4950 |
כתבו פעולה חיצונית ששמה isKaprekar בשפת Java או IsKaprekar בשפת C# , המקבלת מספר שלם חיובי – num . הפעולה תחזיר true אם num הוא מספר "קפרקר מאוזן", אחרת הפעולה תחזיר false .
יש להשתמש בפעולות שכתבתם בסעיפים א–ב.
הניחו שאם מעלים את num בריבוע, מספר הספרות בתוצאה הוא זוגי, ושני החלקים של התוצאה תקינים.
◂ פתרון מלא לשאלה 6
סעיף א
סופרים ספרות len ומחלקים את num ב־ 10, len − k פעמים
מה נדרש: להחזיר את k הספרות השמאליות של num.
רעיון: סופרים את מספר הספרות len של num (מחלקים עותק ב־ 10 עד שמגיע ל־ 0). כדי להשאיר רק k ספרות משמאל צריך "למחוק" את len − k הספרות הימניות – כלומר לחלק את num ב־ 10 (חילוק שלמים) len − k פעמים.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: num = 260043100 (9 ספרות), k = 5: מחלקים ב־ 10 ארבע פעמים: 26004310 → 2600431 → 260043 → 26004. הוחזר 26004. גם leftDigits(81, 1) = 8.
public static int leftDigits(int num, int k)
{
int len = 0;
int temp = num;
while (temp > 0)
{
len++;
temp = temp / 10;
}
for (int i = 0; i < len - k; i++)
{
num = num / 10;
}
return num;
}סעיף ב
return num % 10^k (את 10^k מחשבים בלולאה)
מה נדרש: להחזיר את k הספרות הימניות של num.
רעיון: שארית החלוקה ב־ 10^k היא בדיוק k הספרות הימניות. מחשבים power = 10^k בלולאה (כפל ב־ 10, k פעמים – כך נשארים במספרים שלמים) ומחזירים num % power.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה: num = 260043100, k = 5: power = 100000, 260043100 % 100000 = 43100. גם rightDigits(24502500, 4) = 2500.
public static int rightDigits(int num, int k)
{
int power = 1;
for (int i = 0; i < k; i++)
{
power = power * 10;
}
return num % power;
}סעיף ג
square = num*num; half = (מספר הספרות)/2; return leftDigits(square, half) + rightDigits(square, half) == num;
מה נדרש: לבדוק אם num הוא "קפרקר מאוזן".
רעיון:
לפי ההנחה בשאלה מספר הספרות של הריבוע זוגי; בכל זאת הוספנו בדיקה (אם len אי־זוגי – מחזירים false), כדי שהפעולה תהיה נכונה גם בלי ההנחה.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה:
על המספרים 1–9999 מתקבל true בדיוק עבור 9, 45, 55, 99, 703, 999, 4950, 5050, 7272, 7777, 9999.
הערה: num * num מחושב בטיפוס int, ולכן הפעולה נכונה עבור num עד 46340 (מעבר לכך הריבוע חורג מתחום int). זה מספיק לשאלה, שבה הדוגמה הגדולה היא 4950.
public static boolean isKaprekar(int num)
{
int square = num * num;
int len = 0;
int temp = square;
while (temp > 0)
{
len++;
temp = temp / 10;
}
if (len % 2 != 0)
return false;
int half = len / 2;
int left = leftDigits(square, half);
int right = rightDigits(square, half);
return left + right == num;
}טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | א | 5 |
| ב | למשל n = 4 (כל ריבוע שלם גדול מ־ 1: 4, 9, 16, ...) | |
| 2 | א | speed ≥ max + 10 → 1 ; speed ≤ min − 10 → -1 ; אחרת 0 |
| ב | result[i] = getStatus(speeds[i], max, min) לכל i במערך חדש | |
| ג | סופרים תאים ≠ 0 במערך מ־ getAllStatus ומחזירים count * 2 >= speeds.length | |
| 3 | - | לכל i: place = secretStr.indexOf(playerStr.charAt(i)); place == i → בול, place != -1 → פגיעה, אחרת החמצה. בדוגמה: 1, 2, 1 |
| 4 | א | productID ו־ price מהפרמטרים, quantity = 1, delivery = true |
| ב(1) | return price * quantity; | |
| ב(2) | sum = totalPrice(); אם delivery וגם לא (quantity >= 10 וגם sum > 170) – מוסיפים 100 | |
| ג | int[100]; לכל הזמנה: sums[getProductID()] += getQuantity() | |
| 5 | א | return day == other.getDay() && month == other.getMonth() && year == other.getYear(); |
| ב(1) | return firstNameInitial == other.getFirstNameInitial() && lastNameInitial == other.getLastNameInitial(); | |
| ב(2) | return sameInitials(other) && birthdate.sameDate(other.getBirthdate()); | |
| ג | לולאה כפולה: לקוח i ייחודי אם אין j ≠ i עם clients[i].areSame(clients[j]); אז מדפיסים את getFirstNameInitial() | |
| 6 | א | סופרים ספרות len ומחלקים את num ב־ 10, len − k פעמים |
| ב | return num % 10^k (את 10^k מחשבים בלולאה) | |
| ג | square = num*num; half = (מספר הספרות)/2; return leftDigits(square, half) + rightDigits(square, half) == num; |