מבני נתונים ואלגוריתמים - מחברת קורס/שיעורי בית 6/תשובות
1
[עריכה]נשתמש במספר סימונים ומשפטים פשוטים:
- נגדיר את הרישה ה של מחרוזת כ.
- נגדיר כ את אורך הLIS של שאיברה האחרון הוא .
- נשים לב ש:
- הוא אורך הLIS של .
- מקיים את הנוסחה .
בפתרון נשתמש במערך גלובלי L
המתאר, בכניסה ה, את האיבר הקטן ביותר עד כה המסיים תת-סידרה עולה באורך .
אלה שלבי פעולות הפתרון:
- נאתחל את כל אחד מאיברי
L
ל. - נעבור בלולאה, משמאל לימין, על איברי
X
. כשנגיע לאיבר ה:- נחפש את האיבר הגדול ביותר ב ב
L[1], ..., L[i - 1]
שאינו גדול מX[i]
. - אם מצאנו איבר כזה בכניסה ה של
L
, נקבעL[j + 1] = X[i]
. - אם לא, נקבע
L[1] = X[i]
.
- נחפש את האיבר הגדול ביותר ב ב
- נמצא את האיבר הגדול ביותר ב
L
שאינו , ונחזיר את האינדקס שלו כתשובה המבוקשת.
דוגמה: נניח ש כעת נעבור בלולאה על איברי
|
את המשפט הבא קל להוכיח באינדוקציה:
משפט: בסוף האיטרציה ה של הלולאה:
|
להלן הפסוודו-קוד המתאים:
1 L = Make-Array(n)
2 for i in [1, ..., n]
3 L[i] = ∞
4 for i in [1, ..., n]
5 j = Smaller-Index(L, X[i])
6 L[j + 1] = X[i]
7 max = 0
8 for i in [1, ..., n]
9 if L[i] > max and L[i] < ∞
10 max = L[i]
הנה הסבר לפסוודו-קוד:
- ב1-3 מאתחלים את
L
. קל לראות שהסיבוכיות לינארית. - ב4-6 מעדכנים את
L
על פי ההסבר שראינו למעלה. הפונקציהSmaller-Index
, שמימושה אינו מופיע כאן, ניתנת למימוש בקלות באופן דומה למה שראינו ב[[מבני נתונים ואלגוריתמים - מחברת קורס/#|]] (שים לב שL
ממוין). הסיבוכיות היא . - ב7-10 מחפשים את המקסימום ב
L
. קל לראות שהסיבוכיות לינארית.
2
[עריכה]מצד אחד, כל טור גדול לפחות כמו איברו הראשון. מכאן נקבל: ולכן הטור המקורי הוא .
מצד שני, נקבל , ולכן נחסום מלמעלה את .
עבור ערכי מספיק גדולים, (קל לראות זאת מל'וספיטל, לדוגמה). נגדיר את כאינדקס הראשון בו . נקבל
כדאי לדעת: אפשר לפתור את התרגיל גם בעזרת חסמי האינטגרלים לטורים שראינו. |
3
[עריכה]הפתרון דומה מאד להוכחת הטענה שעצים אדומים-שחורים הם לוגריתמיים. נניח שגובה העץ הוא . מה מספר המפתחות הקטן ביותר היכול להיות בעץ? קל לראות שזה המספר המתקבל כאשר כל אחד מהצמתים הוא מסוג Bar
. במצב זה, היות שעל פי הנתונים כל המסלולים משורש לעלה הם בעלי אותו אורך, נקבל שמספר המפתחות הוא לכל הפחות . הפתרון, לכן, מתקבל על ידי פתירת אי-השוויון :
4
[עריכה]להלן מימוש יעיל אפשרי:
Median
# A min binary heap.
# This will be used to store the half of the larger values.
1 min-bh
# A max binary heap.
# This will be used to store the half of the smaller values.
2 max-bh
# Makes a Median data-structure.
Make-Median()
1 m = Median()
2 m.min-bh = Make-Binary-Heap()
3 m.max-bh = Make-Binary-Heap()
# Adds another value (v) to a Median data-structure (m).
Insert(m, v)
1 if Size(m.max-bh) == 0 or v < Med(m)
2 Insert(m.max-bh)
3 else
4 Insert(m.min-bh)
5 if Size(m.max-bh) > Size(m.min-bh) + 1
6 Insert(m.min-bh, Delete-Max(m.max-bh))
7 else if Size(m.min-bh) > Size(m.max-bh) + 1
8 Insert(m.max-bh, Delete-Min(m.min-bh))
# Returns the median of all the values in a Median data-structure (m).
Med(m)
1 if Size(m.min-bh) == Size(m.max-bh)
2 return (Min(m.min-bh) + Max(m.max-bh)) / 2
3 if Size(m.min-bh) > Size(m.max-bh)
4 return Min(m.min-bh)
5 return Max(m.max-bh)
הנה הסבר לפתרון.
מבנה הנתונים כולל שני תורי קדימויות :max-bh
וmin-bh
(שורות 1-2 של Median
ו2-3 של Make-Median
). הראשונה מיועדת לשמירת חצי האיברים הקטנים יותר, והיא ערימה בינרית השומרת על האיבר הגדול ביותר בראש הערימה; השנייה מיועדת לשמירת חצי האיברים הגדולים יותר, והיא ערימה בינרית השומרת על האיבר הקטן ביותר בראש הערימה.
אם הפרש הגדלים בין גדלי שתי הערימות הוא (כלומר, שתי הערימות מחלקות את כל
האיברים לשני חלקים שווים כמעט בגדלם), אז החציון הוא בהכרח האיבר בראש אחת מהערימות, או ממוצע ראשי האיברים (שורות 1-5 של Med
). זאת אומרת שמציאת החציון דורשת לכל היותר שתי קריאות לSize
, Min
, וMax
של ערימה בינרית - פעולות שהן כל אחת.
כעת נשאר רק לדאוג שהפרש הגדלים בין שתי הערימות הוא אכן . כאשר מכניסים איבר חדש, בוחרים לאיזו ערימה להכניס אותו, על ידי השוואתו לחציון (שורות 1-4 של Insert
). אם אחת הערימות נהיית גדולה מדי (לדוגמה max-bh
), אז שולפים ממנה את איבר הראש, ודוחפים אותו לערימה השנייה.
מבדיקת פעולות הערימה הבינרית שנעשות, קל להווכח שסיבוכיות Insert
היא , וסיבוכיות Med
היא .
5
[עריכה]- הטענה נכונה. נניח שבערימה יש איברים. האיבר האחרון בערימה הוא באינדקס , ואביו (אם יש לו) בהכרח יושב ב. לכן, למרות שהלולאה אינה עוברת על כל האיברים, היא מדלגת רק על ערימות בעלי איבר יחיד, שהן, עפ"י תכונת הערימה, תקינות. הלולאה תתקן כל ערימה שדורשת תיקון, בדיוק מהסיבה שראינו בהרצאה. הסיבוכיות היא . אפשר לראות שהלולאה עוברת על חצי מהאיברים, ולכן היא . מצד שני, היא עושה פחות מBuild-Heap, וזו היתה , ולכן גם לולאה זו .
- הטענה נכונה. אם ילדו השמאלי של איבר במקום נמצא באינדקס , וילדו הימני נמצא באינדקס , אז כל מסלול מהשורש לעלה עובר על סדרת אינדקסים מונוטונית עולה. לכן, אם המערך ממויין, כל מסלול מהשורש לעלה יעבור על סדרת ערכים מונוטונית לא-יורדת. הסיבוכיות הנה מיון מיזוג, כלומר .
- הטענה אינה נכונה, ומפורכת (לדוגמה) ע"י . הסיבוכיות הנה , בדיוק מהניתוח שכבר ראינו לגבי הפתרון מההרצאה.
- הטענה נכונה. היות ש
Bubble-Up(bh, i)
אינו יכול להשפיע על איברים באינדקס מעל , הקוד שקול לסדרת פעולותInsert
. מאותה סיבה, הסיבכויות היא זו של סדרת פעולות Insert, כלומר . - הטענה אינה נכונה, ומפורכת (לדוגמה) ע"י . הסיבכויות היא זו של סדרת פעולות
Insert
, כלומר .
6
[עריכה]הפונקציה Convert(X)
פשוט תחזיר את המערך ממויין בסדר עולה. (אם נשתמש במיון מיזוג, אז הסיבוכיות תהיה ).
נניח שהמערך המקורי הוא , והמערך הממויין הוא .
כל תת-מחרוזת עולה של , נניח , היא תת-מחרוזת משותפת ל ו: היא בהכרח תת-מחרוזת של לפי ההגדרה, והיא תת-מחרוזת של מפני שהיא מחרוזת עולה שאיבריה הם איברי .
לכן, בפרט, תת-המחרוזת המשותפת הארוכה ביותר היא גם בהכרח תת-המחרוזת העולה הארוכה ביותר של .
7
[עריכה]כבר ראינו את נוסחת הנסיגה . נשתמש בזאת כדי להוכיח את הטענה בשאלה באינדוקציה. נראה שקיים כך שתמיד .
הוכחה: (מעבר האינדוקציה) נניח שהטענה נכונה עד (כולל) , ונראה שהיא נכונה גם
ל.
נפתור , ונקבל . עבור , נקבל שמספיק שיתקיים .
מבדיקת מספר העצים השונים, עולה שקיים מתאים גם לבסיס האינדוקציה (המקרים ).