Palindrome String
מחרוזת היא פלינדרום כאשר קוראים אותה משמאל לימין ומימין לשמאל באותו אופן, כמו level. כתוב פונקציה שמקבלת מחרוזת s שמורכבת מאותיות קטנות באנגלית ומחזירה true אם s היא פלינדרום, ו-false אחרת.
פונקציה
- sstring
- המחרוזת באותיות קטנות שיש לבדוק
- מחזירהboolean
- נכון כאשר s נקראת באותה צורה בשני הכיוונים
אילוצים
1 ≤ s.length ≤ 5 × 104sמכיל רק אותיות אנגליות קטנות (aעדz).
דוגמאות
- קלט
- s = "racecar"
- פלט
- true
- הסבר
- משווים מהחוץ פנימה: את
rעםr, אתaעםa, אתcעםc. לאותeשבאמצע אין בת זוג והיא אינה זקוקה לאחת, לכן התשובה היאtrue.
- קלט
- s = "abba"
- פלט
- true
- הסבר
- כשיש אורך זוגי, לכל אות יש בת זוג: שתי האותיות
aתואמות זו לזו ושתי האותיותbתואמות זו לזו, ולכן התשובה היאtrue.
- קלט
- s = "coddy"
- פלט
- false
- הסבר
- האות הראשונה
cוהאות האחרונהyכבר שונות, לכןcoddyאינה פלינדרום והתשובה היאfalse.
שאלת המשך
איך תשנה את שני המצביעים כך שידלגו על רווחים וסימני פיסוק ויתעלמו מהבדלי רישיות, כדי ש־Was it a car or a cat I saw ייחשב לפלינדרום?
רמזים
פתחו אותם אחד אחד. כל רמז חושף קצת יותר.
אם
sהיא פלינדרום, לאיזה תו חייב התו הראשון שלה להיות שווה?התווים באינדקס
iחייבים להיות שווים לתווים באינדקסn-1-i. יש לבדוק כל זוג כזה פעם אחת בלבד, ולכן מספיק לבדוק חצי מהאינדקסים.הצב אינדקס אחד בתחילת המחרוזת ואחד בסופה. השווה בין שתי התווים, החזר
falseאם הם אינם תואמים, והזז את שני האינדקסים צעד אחד פנימה עד שייפגשו.
פתרון
פלינדרום שווה להיפוך של עצמו, לכן אפשר לבנות את ההיפוך ולהשוות ביניהם. אין צורך בעותק: התו הראשון חייב להתאים לתו האחרון, השני לזה שלפני האחרון, וכן הלאה. שני אינדקסים שמתקדמים פנימה בודקים את הזוגות האלה במקום ועוצרים בחוסר ההתאמה הראשון.
השוו את המחרוזת למחרוזת ההפוכה שלה
האינטואיציה
הפוך את s והשווה: ההיפוך של racecar הוא racecar, וההיפוך של coddy הוא yddoc. מחרוזת נקראת אותו דבר בשני הכיוונים בדיוק כאשר היא שווה להיפוך שלה.
הזמן הוא O(n), אבל העותק ההפוך דורש O(n) מקום נוסף, 50,000 תווים כאשר n = 5 × 10^4. גם העבודה תמיד מלאה: אפשר להכריע לגבי coddy לפי האות הראשונה והאחרונה שלו, ובכל זאת הופכים תחילה את כל חמש האותיות.
אלגוריתם
- בנה את ההיפוך של
sבאמצעות פונקציית ההיפוך של השפה או לולאה מהתו האחרון לראשון. - השווה את ההיפוך ל־
s. - החזר
trueאם הם שווים, ו־falseאחרת.
def isPalindrome(s):
return s == s[::-1]שני מצביעים משני הקצוות
האינטואיציה
היפוך מעביר את האינדקס i לאינדקס n-1-i, ולכן s שווה להיפוך שלו בדיוק כאשר s[i] שווה ל-s[n-1-i] עבור כל i. כל זוג מופיע פעמיים בתנאי הזה, ולכן מספיק לבדוק את החצי השמאלי. ב-racecar הזוגות הם (0, 6), (1, 5) ו-(2, 4); לאות e האמצעית באינדקס 3 אין צורך בבן זוג.
הזוג הראשון שאינו שווה מוכיח שהתשובה היא false, ולכן אפשר לקבוע את התוצאה עבור coddy לאחר השוואה אחת. מתבצעות לכל היותר n / 2 השוואות, בזמן O(n), ושני אינדקסים דורשים מקום O(1). ב-R, המחרוזת נקראת תחילה כווקטור של קודי תווים, פעולה שעולה O(n).
אלגוריתם
- הגדר את
left = 0ואתright = n-1. - כל עוד
left < right, השווה ביןs[left]ל־s[right]. - אם הם שונים, החזר
false. - אחרת, הוסף 1 ל־
left, הפחת 1 מ־rightוחזור על הפעולה. - כשהמצביעים נפגשים או חוצים זה את זה, כל זוג התאים: החזר
true.
def isPalindrome(s):
left, right = 0, len(s) - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
מלכודות ומקרי קצה
- החזרת
trueברגע שזוג אחד תואם.abcaעובר את הזוג החיצוני ונכשל בזוג הפנימי, ולכןtrueמוחזר רק אחרי הלולאה. - התחלת
rightב-nבמקום ב-n-1, מה שגורם לקריאה מעבר לסוף (ב-C, אל'\0'המסיים). ב-Lua וב-R האינדקסים נעים מ-1 עדn, ולכן שםrightאכן מתחיל ב-n. - השוואת מחרוזות באמצעות
==ב-C. הביטויreversed == sמשווה בין שני מצביעים, ולכן הוא מחזיר false עבור עותק; יש להשתמש ב-strcmp. - בניית המחרוזת ההפוכה באמצעות
result = result + ch. בכל שלב המחרוזת שנבנתה עד כה מועתקת: בערך1.25 × 10^9העתקות תווים עבור 50,000 אותיות. - אינדוקס של מחרוזת Swift באמצעות מספר שלם: הקוד לא מתקמפל. אפשר לעבור על
s.utf8או להעתיק את התווים למערך.
שאלות נפוצות4
איך בודקים אם מחרוזת היא פלינדרום?
השווה את התו הראשון לאחרון, את השני לזה שלפני האחרון, וכן הלאה לכיוון האמצע. אם זוג כלשהו שונה, המחרוזת אינה פלינדרום. שני אינדקסים שמתחילים בשני הקצוות ומתקדמים פנימה עושים זאת במעבר אחד.
האם אפשר לבדוק אם מילה היא פלינדרום בלי זיכרון נוסף?
כן. בדיקת שני המצביעים קוראת את התווים במקומם ושומרת שני אינדקסים, ולכן משתמשת במקום נוסף של O(1). השוואת s עם ההיפוך שלו קצרה יותר לכתיבה, אבל יוצרת מחרוזת שנייה של n תווים.
מהי סיבוכיות הזמן של בדיקת מחרוזת פלינדרומית?
O(n) עבור מחרוזת באורך n. הבדיקה באמצעות שני מצביעים מבצעת לכל היותר n / 2 השוואות ועוצרת באי-התאמה הראשונה, לכן coddy דורשת השוואה אחת.
האם תו יחיד הוא פלינדרום?
כן, הקריאה זהה בשני הכיוונים. בלולאת שני המצביעים left ו-right מתחילים שניהם באינדקס 0, הלולאה לעולם לא פועלת, והפונקציה מחזירה true.
בעיות דומות
בעיות שמשתמשות באותם רעיונות. פתרון של שתיים או שלוש מהן מקבע את הדפוס.
def isPalindrome(s):
# כתבו כאן קודבדיקה #1
בדיקה #2
בדיקה #3
ארגומנט
s = "racecar"
הפלט הצפוי
true