דילוג לתוכן המרכזי

בגרות במדעי המחשב יסודות מדעי המחשב 899371 - קיץ 2023

1–2 יח"ל · שאלון 899371 · 6 שאלות · 2:30 שעות · פתרון מלא לכל סעיף

בחינת הבגרות במדעי המחשב, יסודות מדעי המחשב, קיץ 2023, כל 6 השאלות כמו בשאלון. לכל סעיף יש תשובה ופתרון מלא: הרעיון, הקוד או המעקב, ובדיקה קצרה. כל קוד מופיע ב-Java וב-C#. נסו לפתור לבד, ואז פתחו את הפתרון.

הוראות הבחינה (כמו בשאלון)

א. משך הבחינה: שעתיים וחצי.
ב. מבנה השאלון ומפתח ההערכה: בשאלון זה שני פרקים.
פרק ראשון – (20×2) – 40 נקודות
פרק שני – (30×2) – 60 נקודות
סך הכול – 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
ד. הוראה מיוחדת:
את כל התוכניות שיש לכתוב בשפת מחשב כתבו בשפה אחת בלבד – Java או C#.
הערה: לא יורדו נקודות אם תכתבו בתוכניות אות גדולה במקום אות קטנה או להפך.

יש לכתוב במחברת הבחינה בלבד. יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.

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

בהצלחה!

השאלות
בשאלון זה שני פרקים.
יש לענות על שאלות משני הפרקים, לפי ההוראות בכל פרק.

הערה: בכל שאלה שנדרשת בה קליטה, אין צורך לבדוק את תקינות הקלט.
לפותרים בשפת Java: בכל שאלה שנדרשת בה קליטה, הניחו שבתוכנית כתובה ההוראה:
Scanner scan = new Scanner (System.in);

פרק ראשון

ענו על שתיים מן השאלות 1–3 (לכל שאלה – 20 נקודות).

שאלה 1 · מעקב אחר לולאה על מערך

נתון מערך arr , המכיל מספרים שלמים:

0123456
arr3496842

נתון קטע תוכנית, הכתוב בשפות Java ו־ C# :

Java

Java
int sum = arr[0];
for (int i=1; i< arr.length; i++)
{
   arr[i] = arr[i] - sum;
   sum += arr[i];
}

C#

C#
int sum = arr[0];
for (int i=1; i< arr.Length; i++)
{
   arr[i] = arr[i] - sum;
   sum += arr[i];
}
א.

עקבו בעזרת טבלת מעקב אחר ביצוע קטע התוכנית, ורשמו את תוכן המערך arr לאחר ביצוע קטע התוכנית.
בטבלת המעקב יש לכלול עמודה עבור כל אחד מן המשתנים האלה: i , arr[i] , sum .

ב.

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

◂ פתרון מלא לשאלה 1

סעיף א

תשובה

arr = {3, 1, 5, −3, 2, −4, −2}

מה נדרש: לעקוב אחרי ביצוע הלולאה על המערך הנתון (עמודות i , arr[i] , sum) ולרשום את המערך בסוף.

רעיון: לפני הלולאה sum = arr[0] = 3. בכל סיבוב מחסירים מ־arr[i] את sum הנוכחי, ואז מוסיפים ל־sum את הערך החדש של arr[i].
שימו לב: sum + (arr[i] − sum) = arr[i] המקורי, כלומר בסוף כל סיבוב sum שווה לערך המקורי של arr[i]. לכן כל תא (חוץ מהראשון) הופך להפרש בין הערך המקורי שלו לערך המקורי של התא שלפניו.

פתרון – טבלת מעקב (לפני הלולאה: sum = 3)

ii < 7 ?arr[i] (אחרי ההשמה)sum (אחרי ההוספה)
1true4 − 3 = 13 + 1 = 4
2true9 − 4 = 54 + 5 = 9
3true6 − 9 = −39 + (−3) = 6
4true8 − 6 = 26 + 2 = 8
5true4 − 8 = −48 + (−4) = 4
6true2 − 4 = −24 + (−2) = 2
7false––

המערך לאחר ביצוע קטע התוכנית:

0123456
arr315−32−4−2

בדיקה: הקטע מדפיס 3 1 5 -3 2 -4 -2, בדיוק כמו בטבלה. וגם לפי הכלל: 4−3=1, 9−4=5, 6−9=−3, 8−6=2, 4−8=−4, 2−4=−2.

טעות נפוצה: להחסיר תמיד את arr[0] או לחשב את sum כסכום הערכים המקוריים. sum מתעדכן בערך החדש של arr[i], ולכן הוא שווה לערך המקורי של התא האחרון שטופל.

סעיף ב

תשובה

למשל {1, 2, 3, 4, 5} (הופך ל־{1, 1, 1, 1, 1}); כל מערך שמתחיל בחיובי ועולה ממש מתאים.

מה נדרש: מערך בגודל 5 שאחרי ביצוע הקטע כל תאיו חיוביים.

רעיון: מסעיף א ראינו שאחרי הביצוע:

•arr[0] לא משתנה;
•כל תא אחר הופך ל־(הערך המקורי שלו) − (הערך המקורי של התא שלפניו).

לכן צריך ש־arr[0] > 0 ושהמערך יהיה עולה ממש (כל ערך גדול מהערך שלפניו).

פתרון: למשל המערך:

01234
arr12345
iarr[i]sum
(לפני)–1
12 − 1 = 12
23 − 2 = 13
34 − 3 = 14
45 − 4 = 15

אחרי הביצוע: 1 , 1 , 1 , 1 , 1 – כל התאים חיוביים.
(כל מערך שמתחיל במספר חיובי ועולה ממש מתאים, למשל 1 , 3 , 6 , 10 , 15 שהופך ל־1 , 2 , 3 , 4 , 5.)

בדיקה: על {1,2,3,4,5} מתקבל 1 1 1 1 1, ועל {1,3,6,10,15} מתקבל 1 2 3 4 5.

טעות נפוצה: לבחור מערך עם שני ערכים שווים צמודים (למשל 1,2,2,…) – התא יהפוך ל־0, ו־0 אינו חיובי.

שאלה 2 · משחק קליעה למטרה

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

•בממוצע הניקוד הוא מעל ל־ 5.0 נקודות.
•ברוב היריות הוא זכה ב־ 6 נקודות ומעלה.
•בירייה אחת או יותר הוא זכה ב־ 10 נקודות.

דוגמה: אדם ירה חמישה חיצים וזכה בניקוד: 5 , 7 , 9 , 3 , 3 . בממוצע הוא זכה ב־ 5.4 נקודות ((3 + 3 + 9 + 7 + 5) / 5)
ולכן הוא הצליח במשחק.

דוגמה נוספת: אדם ירה שישה חיצים וזכה בניקוד: 7 , 6 , 1 , 7 , 8 , 0 . בארבע יריות מתוך השש (כלומר, ברוב היריות שלו) הוא זכה ב־ 6 נקודות ומעלה, ולכן הוא הצליח במשחק.

דוגמה נוספת: אדם ירה שלושה חיצים וזכה בניקוד: 2 , 10 , 0 . באחת מן היריות הוא זכה ב־ 10 נקודות ולכן הוא הצליח במשחק.

כתבו פעולה חיצונית ששמה success בשפת Java או Success בשפת C# , המקבלת מספר שלם – num .
num מציין את מספר החיצים שהאדם ירה למטרה.
הפעולה תקלוט את מספר הנקודות שזכה בהן האדם בעבור כל חץ שהוא ירה.
הפעולה תחזיר true אם האדם הצליח במשחק, אחרת תחזיר הפעולה false .

(20 נקודות)
◂ פתרון מלא לשאלה 2

פתרון

תשובה

קולטים num ציונים, סוכמים, סופרים ציונים ≥ 6 ומסמנים אם היה 10; מחזירים (double)sum/num > 5.0 || countHigh > num/2.0 || hit10.

מה נדרש: פעולה שקולטת num ציונים ומחזירה true אם לפחות אחד משלושת התנאים מתקיים.

רעיון: בלולאה אחת שרצה num פעמים קולטים כל ניקוד ומעדכנים שלושה דברים:

•sum – סכום הנקודות (לחישוב הממוצע);
•countHigh – כמה יריות קיבלו 6 ומעלה;
•hit10 – דגל שמסמן אם הייתה ירייה של 10.

אחרי הלולאה (רק אחרי שכל הקלט נקלט!) בודקים:

•ממוצע: (double) sum / num > 5.0 – ההמרה ל־double חשובה, אחרת החילוק שלם (27/5 = 5 ולא 5.4);
•רוב: countHigh > num / 2.0 – "רוב" = יותר ממחצית היריות (4 מתוך 6 – כן; 3 מתוך 6 – לא);
•hit10.

מחזירים את ה־"או" (||) של שלושת התנאים.

פתרון: הקוד המלא – בלשונית Java/C#. ב־Java משתמשים ב־scan.nextInt() (לפי ההוראה בראש השאלון), וב־C# ב־int.Parse(Console.ReadLine()).

בדיקה: על שלוש הדוגמאות שבשאלה:

•5 , 7 , 9 , 3 , 3 → ממוצע 5.4 → true;
•7 , 6 , 1 , 7 , 8 , 0 → 4 מתוך 6 הם 6 ומעלה (הממוצע 4.83 בלבד) → true;
•2 , 10 , 0 → יש 10 → true.

ומקרים נוספים: 6 , 6 , 0 , 0 → ממוצע 3, בדיוק חצי (לא רוב), אין 10 → false; 5 , 5 → ממוצע 5.0 בדיוק (לא מעל) → false; 6 , 6 , 4 , 4 , 4 → ממוצע 4.8, 2 מתוך 5 → false.

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

הקוד המלא
import java.util.Scanner;

public class Q2
{
    static Scanner scan = new Scanner(System.in);

    public static boolean success(int num)
    {
        int sum = 0;          // סכום הנקודות
        int countHigh = 0;    // מספר היריות שבהן זכה ב־6 נקודות ומעלה
        boolean hit10 = false;
        for (int i = 0; i < num; i++)
        {
            int score = scan.nextInt();
            sum += score;
            if (score >= 6)
                countHigh++;
            if (score == 10)
                hit10 = true;
        }
        double avg = (double) sum / num;
        return avg > 5.0 || countHigh > num / 2.0 || hit10;
    }
}

שאלה 3 · זכאות להנחות בעירייה

מועצת העיר בעיר מסוימת החליטה לזכות את תושביה בהנחות על תשלומים שונים לפי הקריטריונים האלה:

•תושב העיר שגילו 70 ומעלה יהיה זכאי להנחה בתשלום על ארנונה.
•תושב העיר שיש לו 3 ילדים ומעלה יהיה זכאי להנחה בתשלום על גני הילדים.
•תושב העיר שמקום עבודתו בעיר יהיה זכאי להנחה בתשלום על חניה בעיר.

המידע על מידת הזכאות להנחות אלה מיוצג באמצעות מספר תלת־ספרתי, המורכב מן הספרות 1 ו־ 2 בלבד.
הספרה 1 מציינת זכאות להנחה והספרה 2 מציינת אי־זכאות להנחה.
הספרה הראשונה משמאל (ספרת המאות) מציינת זכאות או אי־זכאות להנחה בתשלום על ארנונה,
הספרה האמצעית (ספרת העשרות) מציינת זכאות או אי־זכאות להנחה בתשלום על גני הילדים,
והספרה האחרונה (ספרת האחדות) מציינת זכאות או אי־זכאות להנחה בתשלום על חניה בעיר.

לדוגמה: המספר 122 מציין זכאות להנחה בתשלום על ארנונה ואי־זכאות להנחות בתשלום על גני ילדים ועל חניה.

כתבו פעולה חיצונית ששמה discounts בשפת Java או Discounts בשפת C# , המקבלת שלושה משתנים: age, num, city .
age הוא מספר שלם המציין את הגיל של תושב העיר, num הוא מספר שלם המציין את מספר הילדים של התושב, ו־ city הוא ערך בוליאני המציין אם מקום עבודתו של התושב הוא בעיר (true) או לא (false).
הפעולה מחזירה מספר שלם תלת־ספרתי המציין את הזכאות של התושב להנחות שלעיל.

(20 נקודות)
◂ פתרון מלא לשאלה 3

פתרון

תשובה

מאות = (age >= 70 ? 1 : 2), עשרות = (num >= 3 ? 1 : 2), אחדות = (city ? 1 : 2); מחזירים מאות·100 + עשרות·10 + אחדות.

מה נדרש: לבנות מספר תלת־ספרתי מ־1 ו־2 לפי שלושה תנאים.

רעיון: לכל ספרה מתחילים מ־2 (לא זכאי) ומשנים ל־1 אם התנאי מתקיים:

•ספרת המאות: age >= 70 ("70 ומעלה" – כולל 70);
•ספרת העשרות: num >= 3 ("3 ילדים ומעלה" – כולל 3);
•ספרת האחדות: city.

בסוף מרכיבים את המספר: מאות·100 + עשרות·10 + אחדות.

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה:

agenumcityתוצאה
751false122 (כמו בדוגמה)
403true211
704true111
692false222
300true221

טעות נפוצה: להשתמש ב־> במקום >= (גיל 70 בדיוק ו־3 ילדים בדיוק כן זכאים), או להחזיר את המספר כמחרוזת ("122") במקום מספר שלם.

הקוד המלא
public class Q3
{
    public static int discounts(int age, int num, boolean city)
    {
        int hundreds = 2, tens = 2, units = 2;   // 2 = לא זכאי
        if (age >= 70)
            hundreds = 1;                         // הנחה בארנונה
        if (num >= 3)
            tens = 1;                             // הנחה בגני ילדים
        if (city)
            units = 1;                            // הנחה בחניה
        return hundreds * 100 + tens * 10 + units;
    }
}

פרק שני

ענו על שתיים מן השאלות 4–6 (לכל שאלה – 30 נקודות).

שאלה 4 · זמני שחייה – שיפור והרעה

נתונה המחלקה Results , המייצגת זמני שחיית 50 מטרים של שחיין בתקופה מסוימת.
למחלקה שתי תכונות:

•arr – מערך מטיפוס שלם, המכיל את מספר השניות שארכה שחיית 50 המטרים של השחיין בכל יום בתקופה מסוימת
•name – שם השחיין, מטיפוס מחרוזת

הניחו שקיימות פעולות get/Get ו־ set/Set עבור תכונות המחלקה.

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

א.

כתבו פעולה פנימית ששמה deltas בשפת Java או Deltas בשפת C# , המקבלת פרמטר – isLonger מטיפוס בוליאני, ומחזירה מספר שלם בהתאם לאפיון שלפניכם:

•אם הפרמטר isLonger שהתקבל הוא true , הפעולה תחזיר את סך ההפרשים בימים שנחשבים "הרעה".
•אם הפרמטר isLonger שהתקבל הוא false , הפעולה תחזיר את סך ההפרשים בימים שנחשבים "שיפור".

לדוגמה, עבור המערך arr שלפניכם, אם isLonger הוא true הפעולה תחזיר 14 , ואם isLonger הוא false הפעולה תחזיר 17 .

0123456
arr45525053383842

הסבר: התאים באינדקסים 6 , 3 , 1 מייצגים ימים שנחשבים "הרעה", וסך ההפרשים בהם (4 + 3 + 7) הוא 14 שניות.
התאים באינדקסים 4 , 2 מייצגים ימים שנחשבים "שיפור", וסך ההפרשים בהם (15 + 2) הוא 17 שניות.

ב.

כתבו פעולה פנימית ששמה improving בשפת Java או Improving בשפת C# , המחזירה true אם סך ההפרשים בימים שנחשבים "שיפור" גדול מסך ההפרשים בימים שנחשבים "הרעה". אחרת הפעולה תחזיר false .
למשל, בדוגמה שלעיל הפעולה תחזיר true כיוון שסך ההפרשים בימים שנחשבים "שיפור" גדול מסך ההפרשים בימים שנחשבים "הרעה" (17 > 14).
חובה להיעזר בפעולה שכתבתם בסעיף א.

◂ פתרון מלא לשאלה 4

סעיף א

תשובה

סוכמים מ־i = 1: אם isLonger ו־arr[i] > arr[i-1] מוסיפים arr[i] − arr[i-1]; אם !isLonger ו־arr[i] < arr[i-1] מוסיפים arr[i-1] − arr[i]. בדוגמה: 14 ו־17.

מה נדרש: פעולה פנימית במחלקה Results שסוכמת את ההפרשים בימי "הרעה" (isLonger = true) או בימי "שיפור" (isLonger = false).

רעיון: כל יום (מאינדקס 1) משווים ליום הקודם:

•אם arr[i] > arr[i-1] – יום "הרעה", ההפרש הוא arr[i] - arr[i-1];
•אם arr[i] < arr[i-1] – יום "שיפור", ההפרש (בערך מוחלט) הוא arr[i-1] - arr[i];
•אם שווים – היום אינו נספר באף אחד מהסכומים.

סוכמים רק את סוג הימים שהפרמטר מבקש. הלולאה מתחילה ב־1 כי ליום הראשון אין יום קודם. כיוון שהפעולה פנימית, ניגשים ישירות לתכונה arr.

פתרון: הקוד המלא – בלשונית Java/C# (שתי הפעולות של סעיפים א ו־ב כתובות בתוך המחלקה Results).

בדיקה: על המערך 45 , 52 , 50 , 53 , 38 , 38 , 42:

iarr[i-1] → arr[i]סוגהפרש
145 → 52הרעה7
252 → 50שיפור2
350 → 53הרעה3
453 → 38שיפור15
538 → 38––
638 → 42הרעה4

מתקבל deltas(true) = 14 ו־deltas(false) = 17, כמו בשאלה.

טעות נפוצה: להתחיל את הלולאה מ־0 ולגשת ל־arr[i-1] (חריגה מגבולות המערך), או לספור יום ללא שינוי (38 → 38).

הקוד המלא
    // סעיף א
    public int deltas(boolean isLonger)
    {
        int sum = 0;
        for (int i = 1; i < arr.length; i++)
        {
            if (isLonger && arr[i] > arr[i - 1])        // "הרעה"
                sum += arr[i] - arr[i - 1];
            else if (!isLonger && arr[i] < arr[i - 1])  // "שיפור"
                sum += arr[i - 1] - arr[i];
        }
        return sum;
    }

    // סעיף ב
    public boolean improving()
    {
        return deltas(false) > deltas(true);
    }

סעיף ב

תשובה

return deltas(false) > deltas(true);

מה נדרש: פעולה פנימית שמחזירה true אם סך ההפרשים בימי "שיפור" גדול ממש מסך ההפרשים בימי "הרעה", תוך שימוש בפעולה מסעיף א.

רעיון: deltas(false) נותנת את סך ה"שיפור" ו־deltas(true) את סך ה"הרעה". מחזירים את תוצאת ההשוואה deltas(false) > deltas(true).

פתרון:

public boolean improving()
{
    return deltas(false) > deltas(true);
}

בדיקה: בדוגמה 17 > 14 ולכן true. עבור 40 , 45 , 40 שני הסכומים 5, ולכן false (השיפור לא גדול מההרעה). עבור 40 , 41 , 42 – שיפור 0, הרעה 2 → false.

טעות נפוצה: להשתמש ב־>= – כשהסכומים שווים יש להחזיר false.

הקוד המלא
    // סעיף א
    public int deltas(boolean isLonger)
    {
        int sum = 0;
        for (int i = 1; i < arr.length; i++)
        {
            if (isLonger && arr[i] > arr[i - 1])        // "הרעה"
                sum += arr[i] - arr[i - 1];
            else if (!isLonger && arr[i] < arr[i - 1])  // "שיפור"
                sum += arr[i - 1] - arr[i];
        }
        return sum;
    }

    // סעיף ב
    public boolean improving()
    {
        return deltas(false) > deltas(true);
    }

שאלה 5 · חניון – זמני כניסה ויציאה

המחלקה MyTime מייצגת זמן, ולה שתי תכונות:

•myMinute – מספר שלם חיובי בין 0 ל־ 59 (כולל), המייצג דקה
•myHour – מספר שלם חיובי בין 7 ל־ 23 (כולל), המייצג שעה

הניחו שקיימות פעולות get/Get ו־ set/Set עבור תכונות המחלקה, ופעולה בונה המקבלת ערכים עבור תכונות המחלקה.

לפניכם ממשק המחלקה. אפשר להשתמש בפעולות המחלקה בלי לממש אותן.

תיאור הפעולהכותרת הפעולה
הפעולה מחזירה true אם זמן העצם הנוכחי מוקדם מזמן העצם other , אחרת (כלומר אם הזמן שווה לו או מאוחר ממנו) הפעולה מחזירה false .Java – public boolean before (MyTime other)<br>C# – public bool Before (MyTime other)
הפעולה מחזירה את ההפרש בדקות בערך מוחלט בין זמן העצם הנוכחי ובין זמן העצם other .Java – public int diff (MyTime other)<br>C# – public int Diff (MyTime other)

המחלקה Parking מציגה מידע על מכונית שחנתה בחניון, ולה שלוש תכונות:

•id – מספר לוחית רישוי של המכונית, מטיפוס מחרוזת
•in – זמן כניסת המכונית לחניון, מטיפוס MyTime
•out – זמן יציאת המכונית מן החניון, מטיפוס MyTime

הניחו שקיימות פעולות get/Get ו־ set/Set עבור תכונות המחלקה, ושתכונות המחלקה אינן null .

נתון מערך חד־ממדי cars מטיפוס Parking המכיל מידע על כל המכוניות שחנו בחניון ביממה מסוימת (החניון נפתח ב־ 07:00 ונסגר ב־ 23:59). המערך אינו ממוין ואינו מכיל ערכי null .

א.

כתבו פעולה חיצונית ששמה first בשפת Java או First בשפת C# , המקבלת את המערך cars , ומדפיסה את מספר לוחית הרישוי של המכונית שנכנסה ראשונה לחניון.
הניחו שאין שתי מכוניות שנכנסו לחניון בדיוק באותו הזמן.

ב.(1)

המחיר בחניון נקבע על פי משך החניה. בשעתיים הראשונות (120 דקות) החניה חינם והחל מהדקה ה־ 121 התעריף הוא שקל אחד לכל דקת חניה.

כתבו פעולה פנימית במחלקה Parking ששמה total בשפת Java או Total בשפת C# , המחזירה את סך כל מספר הדקות שהמכונית חנתה בחניון.

(2)

כתבו פעולה חיצונית ששמה sumMoney בשפת Java או SumMoney בשפת C# , המקבלת את המערך cars , ומחזירה את הסכום הכולל ששילמו כל בעלי המכוניות.
אפשר להשתמש בפעולה שכתבתם בסעיף ב(1).

◂ פתרון מלא לשאלה 5

סעיף א

תשובה

חיפוש מינימום עם before על getIn(); מדפיסים cars[minIndex].getId().

מה נדרש: למצוא במערך (לא ממוין) את המכונית עם זמן הכניסה המוקדם ביותר ולהדפיס את מספר הרישוי שלה.

רעיון: חיפוש מינימום רגיל, אלא שההשוואה בין זמנים נעשית בפעולה before של MyTime (אי אפשר להשוות עצמים ב־<). שומרים את האינדקס של המכונית ה"מוקדמת" עד כה (מתחילים מ־0), ועוברים על שאר התאים: אם זמן הכניסה של cars[i] מוקדם מזמן הכניסה של המכונית השמורה – מעדכנים. בסוף מדפיסים את ה־id שלה.

פתרון: הקוד המלא – בלשונית Java/C#. השרשרת cars[i].getIn().before(cars[minIndex].getIn()) – קודם מקבלים את עצם ה־MyTime של זמן הכניסה, ועליו מפעילים את before.

בדיקה: על מערך של 5 מכוניות עם זמני כניסה 09:30 , 07:05 , 08:00 , 13:20 , 07:04 (המכונית האחרונה, "33-333-33", נכנסה ראשונה) – מודפס 33-333-33.

טעות נפוצה: להשוות את זמני ה־out במקום זמני ה־in, או להניח שהמערך ממוין ולהדפיס את cars[0].

הקוד המלא
    // סעיף א
    public static void first(Parking[] cars)
    {
        int minIndex = 0;
        for (int i = 1; i < cars.length; i++)
        {
            if (cars[i].getIn().before(cars[minIndex].getIn()))
                minIndex = i;
        }
        System.out.println(cars[minIndex].getId());
    }

סעיף ב(1)

תשובה

return getIn().diff(getOut());

מה נדרש: פעולה פנימית ב־Parking שמחזירה את משך החניה בדקות.

רעיון: הפעולה diff של MyTime מחזירה בדיוק את ההפרש בדקות בין שני זמנים. מפעילים אותה על זמן הכניסה עם זמן היציאה כפרמטר.

פתרון:

public int total()
{
    return getIn().diff(getOut());
}

(בתוך המחלקה אפשר גם לכתוב ב־Java in.diff(out). ב־C# המילה in היא מילה שמורה, ולכן נוח להשתמש בפעולות GetIn/GetOut.)

בדיקה: כניסה 09:30, יציאה 10:15 → 45; כניסה 13:20, יציאה 23:59 → 639.

הקוד המלא
    // סעיף ב(1) – פעולה פנימית במחלקה Parking
    public int total()
    {
        return getIn().diff(getOut());
    }

סעיף ב(2)

תשובה

לכל מכונית: אם total() > 120 מוסיפים total() − 120; מחזירים את הסכום.

מה נדרש: סכום התשלומים של כל המכוניות.

רעיון: לכל מכונית מחשבים minutes = total(). אם minutes > 120 היא משלמת שקל לכל דקה מהדקה ה־121, כלומר minutes - 120 שקלים; אחרת היא לא משלמת. סוכמים על כל המערך.

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה:

מכוניתכניסהיציאהדקותתשלום
12-345-6709:3010:15450
98-765-4307:0509:051200
11-111-1108:0010:011211
22-222-2213:2023:59639519
33-333-3307:0407:1060

הפעולה החזירה 520 = 0 + 0 + 1 + 519 + 0.

טעות נפוצה: לחייב את כל הדקות (minutes) כשהחניה ארוכה משעתיים, או לחייב 121 − 120 = 1 שקל גם למי שחנה 120 דקות בדיוק (שלא משלם כלל).

הקוד המלא
    // סעיף ב(2)
    public static int sumMoney(Parking[] cars)
    {
        int sum = 0;
        for (int i = 0; i < cars.length; i++)
        {
            int minutes = cars[i].total();
            if (minutes > 120)
                sum += minutes - 120;   // שקל אחד לכל דקה החל מהדקה ה־121
        }
        return sum;
    }

שאלה 6 · פענוח מסר מוצפן

כדי להצפין מסר כלשהו, מערבלים את סדר התווים שמרכיבים אותו (התווים עצמם נשמרים אך מיקומם משתנה).
לדוגמה: לאחר ערבול סדר התווים של המילה World אפשר לקבל את המסר המוצפן rdoWl .

כדי שמקבל המסר המוצפן יוכל לפענח את המסר המקורי של השולח, מצורף למסר המוצפן "מערך מפענח". גודל המערך המפענח הוא כגודל המסר המוצפן, ובכל תא מופיע מספר האינדקס המקורי של כל תו.
לדוגמה: עבור המסר המוצפן rdoWl (של המסר המקורי World), המערך המפענח הוא:

01234
24103

הסבר: התו הראשון במסר המוצפן (r) מופיע במסר המקורי באינדקס 2, התו השני במסר המוצפן (d) מופיע במסר המקורי באינדקס 4, התו השלישי במסר המוצפן (o) מופיע במסר המקורי באינדקס 1, וכן הלאה.

א.

רשמו את המערך המפענח עבור המסר Study , שהוצפן למסר dyutS .

ב.

כתבו פעולה חיצונית ששמה originalText בשפת Java או OriginalText בשפת C# , המקבלת מחרוזת מוצפנת – str ומערך מפענח – arr . הפעולה תחזיר את המחרוזת המקורית.

◂ פתרון מלא לשאלה 6

סעיף א

תשובה

המערך המפענח: {3, 4, 2, 1, 0}

מה נדרש: לכל תו במסר המוצפן dyutS – לרשום את האינדקס שלו במסר המקורי Study.

רעיון: אינדקסים במסר המקורי: S=0 , t=1 , u=2 , d=3 , y=4. עוברים על המסר המוצפן תו אחר תו:

אינדקס במוצפןתואינדקס במקורי
0d3
1y4
2u2
3t1
4S0

פתרון – המערך המפענח:

01234
34210

בדיקה: חישבנו בתוכנית (indexOf של כל תו מוצפן במסר המקורי) וקיבלנו 3 4 2 1 0; ופענוח של dyutS עם המערך הזה בפעולה מסעיף ב החזיר Study.

טעות נפוצה: לרשום את הכיוון ההפוך – לכל תו במקורי את מקומו במוצפן (כך מתקבל 4 , 3 , 2 , 0 , 1). לפי ההגדרה, התא ה־i במערך המפענח מתאים לתו ה־i במוצפן.

סעיף ב

תשובה

orig[arr[i]] = str.charAt(i) לכל i, ואז משרשרים את orig לפי הסדר.

מה נדרש: לבנות את המחרוזת המקורית מהמחרוזת המוצפנת ומהמערך המפענח.

רעיון: arr[i] אומר לאן התו ה־i של המסר המוצפן צריך לחזור. לכן יוצרים מערך תווים orig באורך המחרוזת, ולכל i מציבים orig[arr[i]] = str.charAt(i). אחר כך משרשרים את תווי orig לפי הסדר (מאינדקס 0) למחרוזת התוצאה.

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה:

•originalText("rdoWl", {2,4,1,0,3}) → World (הדוגמה שבשאלה). למשל: r → orig[2], d → orig[4], o → orig[1], W → orig[0], l → orig[3], ובסדר: W o r l d.
•originalText("dyutS", {3,4,2,1,0}) → Study.
•originalText("olleh", {4,3,2,1,0}) → hello (גם עם תווים חוזרים).

טעות נפוצה: לכתוב result += str.charAt(arr[i]) – זה מפעיל את המערך בכיוון ההפוך (עבור rdoWl מתקבל oldrW ולא World).

הקוד המלא
public class Q6
{
    public static String originalText(String str, int[] arr)
    {
        char[] orig = new char[str.length()];
        for (int i = 0; i < str.length(); i++)
            orig[arr[i]] = str.charAt(i);     // התו ה־i במסר המוצפן חוזר למקומו המקורי
        String result = "";
        for (int i = 0; i < orig.length; i++)
            result += orig[i];
        return result;
    }
}
טבלת התשובות
שאלהסעיףתשובה
1א

arr = {3, 1, 5, −3, 2, −4, −2}

ב

למשל {1, 2, 3, 4, 5} (הופך ל־{1, 1, 1, 1, 1}); כל מערך שמתחיל בחיובי ועולה ממש מתאים.

2-

קולטים num ציונים, סוכמים, סופרים ציונים ≥ 6 ומסמנים אם היה 10; מחזירים (double)sum/num > 5.0 || countHigh > num/2.0 || hit10.

3-

מאות = (age >= 70 ? 1 : 2), עשרות = (num >= 3 ? 1 : 2), אחדות = (city ? 1 : 2); מחזירים מאות·100 + עשרות·10 + אחדות.

4א

סוכמים מ־i = 1: אם isLonger ו־arr[i] > arr[i-1] מוסיפים arr[i] − arr[i-1]; אם !isLonger ו־arr[i] < arr[i-1] מוסיפים arr[i-1] − arr[i]. בדוגמה: 14 ו־17.

ב

return deltas(false) > deltas(true);

5א

חיפוש מינימום עם before על getIn(); מדפיסים cars[minIndex].getId().

ב(1)

return getIn().diff(getOut());

ב(2)

לכל מכונית: אם total() > 120 מוסיפים total() − 120; מחזירים את הסכום.

6א

המערך המפענח: {3, 4, 2, 1, 0}

ב

orig[arr[i]] = str.charAt(i) לכל i, ואז משרשרים את orig לפי הסדר.

כל האתר במבט אחד

קיצורי דרך לכל הכלים, הבגרויות והקורסים

GuyAI הוא המורה הפרטי המתקדם בישראל, המבוסס על מודלי הבינה המלאכותית החזקים בעולם בשילוב הידע הפדגוגי של GOOL. המערכת מספקת פתרונות לכל המקצועות ולכל הרמות - מיסודי ועד אקדמיה, וממתמטיקה ועד היסטוריה.