تمرین و حل مسئله یکی از بهترین روشها برای یادگیری و تقویت مهارتهای برنامهنویسی است. در این مقاله، ۱۰ تمرین ساده اما مفید برای یادگیری پایتون ارائه میکنیم. هر تمرین شامل توضیح مسئله، راهنمایی کوتاه، و یک پاسخ تشریحی است. این تمرینها برای برنامهنویسان مبتدی تا متوسط مناسب هستند. بیایید مستقیماً سراغ تمرین اول برویم.
تمرین ۱: شمارش تکرار حروف یک رشته
توضیح مسئله
برنامهای بنویسید که یک رشته ورودی را دریافت کند و تعداد تکرار هر حرف را در آن نمایش دهد. خروجی باید بهصورت یک دیکشنری باشد که کلیدهای آن حروف و مقادیر آن تعداد تکرار هر حرف باشد.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- میتوانید از یک
dictبرای نگهداری تعداد تکرار هر کاراکتر استفاده کنید. - از
collections.Counterهم میتوان استفاده کرد که راه سادهتری است.
پاسخ تشریحی
روش ۱: استفاده از حلقه for
توضیح کد:
- یک دیکشنری خالی به نام
char_countایجاد میکنیم. - با یک حلقه
for، روی تمام کاراکترهای متن ورودی پیمایش میکنیم. - اگر کاراکتر در دیکشنری وجود داشت، مقدار آن را یک واحد افزایش میدهیم. در غیر این صورت، مقدار اولیهی آن را ۱ قرار میدهیم.
- در نهایت، دیکشنری نهایی که شامل شمارش هر کاراکتر است، برگردانده میشود.
روش ۲: استفاده از collections.Counter
چرا این روش بهتر است؟
- این روش فقط در دو خط کد انجام میشود.
Counterبهصورت داخلی همین عملیات شمارش را بهینه انجام میدهد.
تمرین ۲: پیدا کردن عدد گمشده در لیست
توضیح مسئله
یک لیست از اعداد متوالی از ۱ تا n داریم که یکی از اعداد آن بهطور تصادفی حذف شده است. برنامهای بنویسید که عدد گمشده را پیدا کند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- مجموع دنباله حسابی از ۱ تا n را میتوان با فرمول
n * (n + 1) // 2محاسبه کرد. - مجموع مقادیر موجود در لیست را از این مقدار کم کنید تا عدد گمشده را پیدا کنید.
- همچنین میتوان از عملیات
setاستفاده کرد.
پاسخ تشریحی
روش ۱: استفاده از مجموع دنباله حسابی
توضیح کد:
- تعداد کل اعداد (
n) را برابر با طول لیست بهعلاوهی ۱ در نظر میگیریم. - مجموع مورد انتظار دنبالهی ۱ تا
nرا با استفاده از فرمول دنباله حسابی محاسبه میکنیم. - مجموع مقادیر واقعی در لیست را محاسبه کرده و از مجموع مورد انتظار کم میکنیم.
- مقدار باقیمانده همان عدد گمشده است.
روش ۲: استفاده از set
چرا این روش جالب است؟
- از مزیتهای
setاستفاده میکند که جستجو در آن سریع است. - نیازی به انجام محاسبات ریاضی ندارد.
- کد خواناتر است.
تمرین ۳: تشخیص عدد اول
توضیح مسئله
برنامهای بنویسید که یک عدد را دریافت کند و تشخیص دهد که آیا عدد اول است یا خیر.
تعریف عدد اول
عدد اول، عددی بزرگتر از ۱ است که فقط دو مقسومعلیه دارد: ۱ و خودش.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
ورودی:
خروجی:
راهنمایی
- عددی که بر عددی کوچکتر از خودش (غیر از ۱) بخشپذیر باشد، اول نیست.
- نیازی به بررسی مقسومعلیههای بزرگتر از رادیکال آن عدد نیست، زیرا اگر عددی مقسومعلیه بزرگتر داشته باشد، یک مقسومعلیه کوچکتر از رادیکال هم خواهد داشت.
- بررسی بخشپذیری تا
√nزمان اجرای بهتری نسبت به بررسی همه اعداد دارد.
پاسخ تشریحی
روش ۱: بررسی تمامی مقسومعلیهها تا n
مشکل این روش:
- زمان اجرای آن
O(n)است، زیرا برای هر مقدارnباید تاn-1بررسی انجام شود. - برای اعداد بزرگ، کند خواهد شد.
روش ۲: بهینهسازی با بررسی تا √n
چرا این روش بهتر است؟
- به جای بررسی تمام اعداد تا
n، فقط تا√nرا بررسی میکنیم. - به جای بررسی تمام اعداد، فقط اعداد فرد و غیرقابل تقسیم بر ۲ و ۳ را چک میکنیم.
- اجرای سریعتری نسبت به روش اول دارد، مخصوصاً برای اعداد بزرگ.
تمرین ۴: برعکس کردن رشته (بدون استفاده از توابع آماده)
توضیح مسئله
برنامهای بنویسید که یک رشته ورودی را دریافت کرده و آن را بدون استفاده از توابع آماده (مثل [::-1] یا reversed()) برعکس کند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- از یک حلقه
forبرای پیمایش از انتهای رشته به ابتدا استفاده کنید. - از لیست و متد
join()برای ساختن رشته برعکس استفاده کنید. - روش دیگر، استفاده از دو اشارهگر (Two Pointers) است که از دو سمت رشته حرکت میکنند و کاراکترها را جابهجا میکنند.
پاسخ تشریحی
روش ۱: استفاده از حلقه for
توضیح کد:
- متغیر
reversed_textرا بهصورت یک رشته خالی تعریف میکنیم. - با پیمایش روی
text، هر کاراکتر جدید را در ابتدایreversed_textاضافه میکنیم. - در نهایت، رشته معکوس شده را برمیگردانیم.
مشکل این روش:
- این روش کار میکند اما از نظر کارایی بهینه نیست، زیرا هر بار یک رشته جدید ساخته میشود (عملیات اضافه کردن به ابتدای رشته کند است).
روش ۲: استفاده از لیست و join()
چرا این روش بهتر است؟
- لیستها تغییرپذیر هستند و عملیات
insert(0, char)سریعتر از الحاق مستقیم به ابتدای رشته است. - در نهایت با
join()تمام عناصر را به رشته تبدیل میکنیم.
روش ۳: استفاده از دو اشارهگر (بهینهترین روش)
چرا این روش بهتر است؟
- از دو اشارهگر برای جابهجایی مقدارها استفاده میکند.
- پیچیدگی زمانی
O(n/2)دارد که سریعتر از روشهای قبلی است. - این روش دقیقاً همانکاری را انجام میدهد که در توابع داخلی
[::-1]یاreversed()انجام میشود.
تمرین ۵: حذف عناصر تکراری از یک لیست (حفظ ترتیب اولیه)
توضیح مسئله
برنامهای بنویسید که یک لیست از اعداد یا رشتهها را دریافت کند و عناصر تکراری را حذف کند، اما ترتیب اولیه لیست را حفظ کند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- از
setبرای حذف تکراریها استفاده کنید، اما چونsetترتیب را حفظ نمیکند، نمیتوان آن را مستقیماً به کار برد. - از یک لیست کمکی برای نگهداشتن عناصر یکتا استفاده کنید.
- روش دیگر، استفاده از
OrderedDictدرcollectionsاست که میتواند هم ترتیب را حفظ کند و هم عناصر تکراری را حذف کند.
پاسخ تشریحی
روش ۱: استفاده از لیست و set
توضیح کد:
- یک لیست
unique_listبرای ذخیره مقادیر یکتا و یکsetبرای ذخیره موارد دیدهشده ایجاد میکنیم. - در حلقه
for، بررسی میکنیم که آیا عنصر قبلاً درseenوجود دارد یا نه. - اگر وجود ندارد، آن را به لیست
unique_listاضافه کرده و درsetثبت میکنیم.
چرا این روش خوب است؟
✅ ترتیب عناصر را حفظ میکند.
✅ پیچیدگی زمانی O(n) دارد، چون هر عنصر فقط یک بار پردازش میشود.
روش ۲: استفاده از OrderedDict
چرا این روش جالب است؟
OrderedDict.fromkeys(lst)بهطور خودکار کلیدها (عناصر لیست) را در ترتیب اصلی حفظ میکند و تکراریها را حذف میکند.- بسیار کوتاه و خوانا است!
- زمان اجرای مشابه روش قبلی (
O(n)) دارد.
تمرین ۶: مجموع اعداد موجود در یک رشته
توضیح مسئله
برنامهای بنویسید که یک رشتهی شامل حروف و اعداد را دریافت کرده و مجموع تمام اعداد داخل آن را محاسبه کند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- میتوان از یک حلقه برای پیمایش روی رشته استفاده کرد و اعداد را استخراج کرد.
- از ماژول
re(Regular Expressions) نیز میتوان برای یافتن سریع تمام اعداد استفاده کرد.
پاسخ تشریحی
روش ۱: استفاده از حلقه و متغیر کمکی
توضیح کد:
- دو متغیر
total_sumبرای ذخیره مجموع وcurrent_numberبرای نگهداری عدد فعلی تعریف میکنیم. - روی
textپیمایش میکنیم:
- اگر کاراکتر عددی بود، آن را به
current_numberاضافه میکنیم. - اگر غیرعددی بود، مقدار
current_numberرا به عدد تبدیل کرده و به مجموع اضافه میکنیم. - در انتها، اگر رشته به عدد ختم شود، بررسی میکنیم که مقدار نهایی اضافه شود.
- مقدار نهایی
total_sumرا برمیگردانیم.
چرا این روش کار میکند؟
✅ از حلقه for و متغیر کمکی استفاده کرده و نیازی به کتابخانه اضافی ندارد.
✅ برای پردازش رشتههایی که شامل اعداد طولانی هستند، عملکرد مناسبی دارد.
روش ۲: استفاده از re (تعبیر با عبارات منظم)
چرا این روش بهتر است؟
re.findall(r'\d+', text)تمام اعداد متوالی را در یک لیست استخراج میکند.map(int, numbers)اعداد را از رشته به عدد تبدیل میکند.- بسیار سریع و خوانا است و در یک خط کد کار را انجام میدهد!
تمرین ۷: یافتن دو عدد در لیست که مجموعشان مقدار مشخصی شود
توضیح مسئله
برنامهای بنویسید که یک لیست از اعداد و یک عدد هدف دریافت کند و دو عدد از لیست را پیدا کند که مجموعشان برابر عدد هدف باشد. اگر چنین زوجی وجود نداشت، مقدار None برگرداند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- میتوان از حلقه تو در تو استفاده کرد، اما این روش کند است (
O(n²)). - روش بهینهتر استفاده از
setیاdictبرای بررسی سریعتر مقادیر است (O(n)).
پاسخ تشریحی
روش ۱: استفاده از دو حلقه (روش ساده اما ناکارآمد)
چرا این روش کند است؟
- در بدترین حالت، همه جفتها را بررسی میکند (
O(n²)). - برای لیستهای طولانی، کارایی خوبی ندارد.
روش ۲: استفاده از set برای بهینهسازی
چرا این روش بهتر است؟
✅ زمان اجرا O(n) است، چون فقط یک بار روی لیست حرکت میکنیم.
✅ از set برای بررسی سریعتر (O(1)) استفاده میشود.
تمرین ۸: تبدیل حروف کوچک به بزرگ و برعکس
توضیح مسئله
برنامهای بنویسید که یک رشته ورودی را دریافت کند و تمام حروف کوچک را به بزرگ و حروف بزرگ را به کوچک تبدیل کند. بقیه کاراکترها (اعداد، فاصله، نشانهگذاری و …) بدون تغییر باقی بمانند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- میتوان از حلقه
forو متدهایisupper()وislower()برای بررسی نوع حروف استفاده کرد. - روش بهینهتر استفاده از متد آماده
swapcase()است که همین کار را انجام میدهد.
پاسخ تشریحی
روش ۱: استفاده از for و بررسی دستی
چرا این روش کار میکند؟
✅ از متدهای isupper() و islower() برای تشخیص حروف بزرگ و کوچک استفاده کردهایم.
✅ در هر مرحله فقط یک تغییر انجام میشود، بنابراین ترتیب حفظ میشود.
روش ۲: استفاده از متد آماده swapcase()
چرا این روش بهتر است؟
- بسیار سریع و خوانا است.
- در یک خط کد عملیات را انجام میدهد.
- از نظر عملکرد، متد
swapcase()از لحاظ بهینهسازی داخلی سریعتر از حلقه دستی است.
تمرین ۹: پیدا کردن طولانیترین کلمه در یک جمله
توضیح مسئله
برنامهای بنویسید که یک جمله را دریافت کند و طولانیترین کلمه را از آن استخراج کند. اگر چندین کلمه با بیشترین طول وجود داشتند، اولین مورد را برگرداند.
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- میتوان از
split()برای جدا کردن کلمات جمله استفاده کرد. - از حلقه
forبرای بررسی طول هر کلمه استفاده کنید. - روش سادهتر، استفاده از
max()همراه با پارامترkey=lenاست.
پاسخ تشریحی
روش ۱: استفاده از for و متغیر کمکی
چرا این روش کار میکند؟
✅ ابتدا جمله را به لیستی از کلمات تبدیل میکنیم.
✅ سپس با یک حلقه، طول هر کلمه را بررسی کرده و در صورت نیاز مقدار longest را بهروز میکنیم.
روش ۲: استفاده از max() با key=len
چرا این روش بهتر است؟
✅ از تابع max() برای یافتن طولانیترین مقدار در یک خط استفاده میکنیم.
✅ کد سادهتر و خواناتر است.
✅ زمان اجرا بهینهتر است زیرا مستقیماً مقدار بیشینه را پیدا میکند.
تمرین ۱۰: فاکتوریل یک عدد (بهینه و بازگشتی)
توضیح مسئله
برنامهای بنویسید که یک عدد صحیح مثبت دریافت کرده و فاکتوریل آن را محاسبه کند.
(فاکتوریل n! برابر است با n × (n-1) × ... × 2 × 1 و مقدار 0! برابر ۱ است.)
مثال ورودی و خروجی
ورودی:
خروجی مورد انتظار:
راهنمایی
- میتوان از یک حلقه
forبرای محاسبه فاکتوریل استفاده کرد. - روش بازگشتی (Recursive) نیز برای این مسئله پرکاربرد است.
- برای اعداد خیلی بزرگ،
math.factorial()سریعترین گزینه است.
پاسخ تشریحی
روش ۱: استفاده از for (روش ساده و بهینه)
چرا این روش خوب است؟
✅ بدون نیاز به تابع بازگشتی کار میکند.
✅ پیچیدگی زمانی O(n) دارد که برای مقادیر بزرگ مناسب است.
✅ حلقه for ساده و خواناست.
روش ۲: استفاده از بازگشت (Recursive)
مشکل این روش چیست؟
- ممکن است باعث سرریز شدن پشته (Stack Overflow) برای اعداد بزرگ شود.
- سرعت اجرای آن نسبت به روش
forکندتر است. - پیچیدگی زمانی
O(n)است، اما بهخاطر فراخوانیهای بازگشتی، حافظه بیشتری مصرف میکند.
روش ۳: استفاده از math.factorial() (بهترین روش برای اعداد خیلی بزرگ)
چرا این روش عالی است؟
✅ از الگوریتمهای داخلی بهینهشده در Python استفاده میکند.
✅ برای اعداد خیلی بزرگ (مثل 100!) بدون خطای پشته اجرا میشود.
✅ خواناترین روش است.
جمعبندی
در این مقاله، ۱۰ تمرین کاربردی برای تقویت مهارتهای پایتون را بررسی کردیم. این تمرینها از مسائل ساده تا تکنیکهای بهینهسازی را پوشش دادند و برای توسعه مهارتهای برنامهنویسی مفید هستند.
✅ مباحث کلیدی که یاد گرفتیم:
- کار با رشتهها و لیستها (مثل برعکس کردن رشته و حذف عناصر تکراری)
- کار با اعداد و ریاضیات (مثل فاکتوریل و تشخیص عدد اول)
- مدیریت دادهها و مجموعهها (مثل شمارش تکرار کاراکترها و یافتن دو عدد با مجموع مشخص)
- بهینهسازی الگوریتمها (استفاده از
set،dictوmathبرای بهبود کارایی) - استفاده از کتابخانههای داخلی پایتون (
re،collections،math) برای حل مسائل بهصورت کارآمد
📌 تمرین بیشتر:
اگر میخواهی مهارتهای پایتونت را بیشتر تقویت کنی، میتوانی:
- تمرینهای مشابه را با دادههای مختلف اجرا کنی.
- سعی کنی روشهای بهینهتر و جدیدتری برای حل مسائل پیدا کنی.
- همین تمرینها را با استفاده از برنامهنویسی شیگرا (OOP) پیادهسازی کنی.
دیدگاهها