Remove Vowels
מקבלים מחרוזת s שמורכבת מאותיות באנגלית. החזירו את המחרוזת שמתקבלת לאחר מחיקת כל התנועות ממנה. התנועות הן a, e, i, o ו-u, באותיות קטנות או גדולות; כאן y אינה תנועה. האותיות שנשארות שומרות על הסדר ועל רישיות האותיות שלהן.
פונקציה
- sstring
- מחרוזת האותיות באנגלית שיש לנקות
- מחזירהstring
- s עם כל התנועות שהוסרו ושאר האותיות בסדרן המקורי
אילוצים
1 ≤ s.length ≤ 3 × 104sמכילה רק אותיות באנגלית (aעדz,AעדZ).sמכילה לפחות אות אחת שאינה תנועה, ולכן התשובה לעולם אינה ריקה.
דוגמאות
- קלט
- s = "Interview"
- פלט
- "ntrvw"
- הסבר
- מחיקת
I,e,iו-eמתוךInterviewמשאירה אתn,t,r,v,wבסדר הזה. גםIהגדולה היא תנועה, ולכן היא נמחקת.
- קלט
- s = "rhythm"
- פלט
- "rhythm"
- הסבר
- ב־
rhythmאיןa,e,i,oאוu, לכן שום דבר לא נמחק. האותyשבו אינה מופיעה ברשימת התנועות ונשארת.
- קלט
- s = "EuropeanUnion"
- פלט
- "rpnnn"
- הסבר
- שמונה מתוך שלוש עשרה האותיות של
EuropeanUnionהן תנועות, כולל האותיות הגדולותEו־U. חמש העיצורים שנותרו,r,p,n,n,n, שומרים על הסדר שלהם ונקראיםrpnnn.
+17 בדיקות נסתרות בשליחה
שאלת המשך
מה אם הטקסט יכול להכיל כל אות Unicode, כמו É או ö? אילו מהן הן תנועות, וכיצד משתנה הבדיקה שלך?
רמזים
פתחו אותם אחד אחד. כל רמז חושף קצת יותר.
אילו אותיות של
sמופיעות בתשובה, והאם הסדר שלהן משתנה?במקום למחוק תנועות, צרו מחרוזת חדשה מהאותיות שאתם משאירים. זכרו שגם
A,E,I,Oו־Uהן תנועות.עבור על המחרוזת פעם אחת. הוסף כל תו שאינו אחד מהתווים
aeiouAEIOUלבונה או לרשימה, וחבר אותם למחרוזת בסוף.
פתרון
הסרת תווים מאמצע מחרוזת היא פעולה יקרה אם עושים זאת מחיקה אחת בכל פעם, כי כל מה שאחרי הרווח זז. תוכנית טובה יותר היא לבנות את התוצאה במקום זאת: עוברים על המחרוזת פעם אחת ומעתיקים כל אות שאינה תנועה. הפרטים שחשוב לדייק בהם הם התנועות הגדולות ואופן הרכבת התוצאה.
מחקו כל תנועה במעבר נפרד
האינטואיציה
רוב השפות יכולות למחוק כל עותק של תו אחד ממחרוזת בקריאה אחת: מחליפים אותו בכלום. עושים זאת עשר פעמים, פעם אחת עבור כל אחד מהתווים a e i o u A E I O U, וכך לא נשארת אף תנועה. העיצורים לעולם אינם נוגעים בהם, ולכן הם שומרים על הסדר ועל האותיות הגדולות והקטנות שלהם.
עבור Interview, המעבר עבור e נותן Intrviw, המעבר עבור i נותן Intrvw, והמעבר עבור I נותן ntrvw. שבעת המעברים האחרים אינם מוצאים דבר להסיר.
כל מעבר קורא את כל המחרוזת הנוכחית, ולכן העבודה דורשת בערך 10n צעדים של תווים. זה עדיין O(n), כי עשר הוא קבוע, אבל עבור 3 × 10^4 אותיות פירוש הדבר 3 × 10^5 צעדים, בעוד שמעבר יחיד דורש 3 × 10^4.
אלגוריתם
- קח את עשר אותיות התנועה
aeiouAEIOUאחת בכל פעם. - עבור כל אחת מהן, החלף כל מופע שלה בתוך
sבכלום. - לאחר עשרת המעברים, החזר את מה שנותר מ־
s.
def removeVowels(s):
for vowel in "aeiouAEIOU":
s = s.replace(vowel, "") # one full pass for this letter
return sמעבר אחד ששומר על העיצורים
האינטואיציה
הפכו את המשימה: במקום למחוק תנועות, אספו את כל השאר. עברו על s פעם אחת, ובדקו לגבי כל תו אם הוא אחת מעשר אותיות התנועה. אם לא, הוסיפו אותו לתוצאה. מכיוון שאתם מוסיפים לפי סדר הקריאה ולא משנים אף תו, הסדר והאותיות הגדולות והקטנות של העיצורים יישארו בדיוק כפי שהיו בקלט.
עבור EuropeanUnion, המעבר מדלג על E, u, o, e, a, U, i ו-o, ומוסיף את r, p, n, n, n: התוצאה היא rpnnn.
כל תו דורש בדיקה אחת בזמן קבוע (חיפוש בקבוצה, switch או חיפוש במחרוזת בת עשר אותיות), ולכן זמן הריצה הוא O(n). אספו את האותיות בבונה מחרוזות או ברשימה והמירו אותן למחרוזת פעם אחת בסוף; הגדלת מחרוזת בלתי ניתנת לשינוי באמצעות += תעתיק אותה בכל שלב. הפלט עצמו דורש O(n) מקום.
אלגוריתם
- התחל בונה ריק עבור התוצאה.
- עבור על
sתו אחד בכל פעם. - אם התו אינו אחד מהתווים
aeiouAEIOU, הוסף אותו לבונה. - החזר את הבונה כמחרוזת.
def removeVowels(s):
vowels = set("aeiouAEIOU")
kept = []
for ch in s:
if ch not in vowels:
kept.append(ch)
# Joining a list once avoids rebuilding the string on every character.
return "".join(kept)
מלכודות ומקרי קצה
רוב התשובות השגויות נובעות מבדיקת התנועות או מהאופן שבו מחרוזת התוצאה גדלה.
- שוכחים תנועות באותיות גדולות. בדיקה של
aeiouבלבד הופכת אתInterviewל-Intrvwבמקום ל-ntrvw. בדקו את כל עשר האותיות, או הפכו את האותיות לקטנות לפני הבדיקה, והשאירו את האות המקורית בפלט. - משנים את האותיות שנשמרות לאותיות קטנות. אם הופכים את כל המחרוזת לאותיות קטנות כדי לקצר את הבדיקה,
QUEUEINGהופכת ל-qngבמקום ל-QNG. הפכו לאותיות קטנות רק את העותק שאתם בודקים, והוסיפו את האות המקורית. - מוחקים תוך כדי מעבר קדימה לפי אינדקס. הסרת
s[i]מזיזה את האות הבאה למיקוםi, ואזi++מדלג עליה, כך ש-aabהופכת ל-ab. בנו מחרוזת חדשה, או עברו בעזרת מיקומי קריאה וכתיבה נפרדים. - מגדילים מחרוזת בלתי ניתנת לשינוי באמצעות
+=בתוך לולאה. ב-Java או ב-C# כל שלב מעתיק את המחרוזת כולה — בערך4.5 × 10^8העתקות תווים עבור3 × 10^4אותיות. השתמשו בבונה מחרוזות או ברשימה, וחברו אותה פעם אחת.
שאלות נפוצות4
איך מסירים תנועות ממחרוזת?
עבור על המחרוזת פעם אחת והעתק כל אות שאינה a, e, i, o או u (באותיות גדולות או קטנות) אל בונה מחרוזות או אל רשימה. חבר אותם למחרוזת בסוף. הסדר והגודל של האותיות שנשמרו יישארו כפי שהיו.
מהי סיבוכיות הזמן של הסרת תנועות?
מעבר אחד הוא בזמן O(n), כי כל תו עובר בדיקת תנועה אחת בזמן קבוע. הפלט דורש O(n) מקום במקרה הגרוע ביותר, כאשר אין ב-s תנועות כלל. קריאה ל-replace פעם אחת עבור כל תנועה היא גם O(n), אבל היא קוראת את המחרוזת עשר פעמים.
אפשר להסיר תנועות באמצעות ביטוי רגולרי?
כן. החלפת התבנית [aeiouAEIOU] במחרוזת ריקה עושה זאת בקריאה אחת ברוב השפות. היא רצה ב־O(n), כמו הלולאה, אבל מראיינים בדרך כלל מבקשים ממך לכתוב את הלולאה כדי שיוכלו לראות את בדיקת התנועות ואת אופן בניית התוצאה.
למה לא למחוק את התנועות מהמחרוזת במקום?
מחיקת תו אחד מאמצע המחרוזת מזיזה שמאלה כל תו שבא אחריו, ולכן מחיקות רבות עלולות לעלות O(n²). אפשר לבצע זאת במקום ב־O(n) באמצעות שני אינדקסים: אחד שקורא כל תו ואחד שכותב את האות הבאה שיש להשאיר. אבל ברוב השפות אי אפשר לשנות מחרוזות, ולכן יצירת מחרוזת חדשה היא הדרך הטבעית.
בעיות דומות
בעיות שמשתמשות באותם רעיונות. פתרון של שתיים או שלוש מהן מקבע את הדפוס.
Python
def removeVowels(s):
# כתבו כאן את הקודמקרה 1
מקרה 2
מקרה 3
קלט
s = "Interview"
צפוי
"ntrvw"