حمید ملارضا
حمید ملارضا
خواندن ۶ دقیقه·۲ سال پیش

چطور با جاوااسکریپت سوالات کوئرا رو حل کنیم؟

بسم الله الرحمن الرحیم

کوئرا از موتور جاوااسکریپتی به نام v8 استفاده میکنه. با این روش برای گرفتن ورودی می‌تونیم از تابع readline استفاده کنیم. برای مثال:

const name = readline(); console.log(`Hello ${name}!`);

با استفاده از v8 گرفتن ورودی از کنسول آسون‌تر میشه اما خبر بد اینه که نصب این موتور کار آسونی نیست. برای همین به نظرم دوتا راه آسون داریم.

راه اول: استفاده از داکر

به کمک ایمیج داکری مثل این، خیلی آسون و راحت می‌تونیم کدهای خودمون رو اجرا کنیم. برای آشنایی بیشتر بهتره مستندات اصلی رو در گیت‌هاب بخونید اما به عنوان یه راهنمایی کوتاه:

۱- لازمه داکر رو روی سیستم نصب کرده باشین. اگر نصب نکردین می‌تونید از این لینک نصب کنید.

۲- ایمیج رو pull کنید:

docker pull hamidmolareza/d8

۳- مثل این قالب، یک فایل جاوااسکریپت (مثلا) به نام program.js ایجاد کنید و کدتون رو توش قرار بدین.

۴- ترمینال رو در دایرکتوری کد، باز کنید و از دستور زیر برای اجرا کردن برنامه استفاده کنید:

docker run --rm -it -v $PWD:/src hamidmolareza/d8 run /src/program.js

همین! دیگه لازم نیست درگیر سختی‌های نصب v8 بشین. هرجا که داکر نصب بشه (تقریبا همه‌جا) می‌تونید به سادگی از v8 استفاده کنید.

این ایمیج، امکانات مختلف دیگه‌ای هم داره که بهتره مستندات اصلی رو بخونید. مثلا می‌تونید یک یا چندتا فایل ورودی براش تعریف کنید تا هربار مجبور نباشید ورودی‌ها رو به صورت دستی به برنامه بدین. یا می‌تونید مستقیما از شل d8 استفاده کنید و...


راه دوم: استفاده از nodejs برای کسایی که با داکر آشنا نیستن

داکر یه ابزار بسیار رایج و کاربردی برای برنامه‌نویس‌ها (خصوصا بک‌اند، devops و...) هستش و تقریبا مثل گیت، یادگیریش واجبه ولی اگر تازه شروع به یادگیری برنامه‌نویسی کردین یا قرار نیست به صورت حرفه‌ای برنامه‌نویسی کنید می‌تونید بیخیال v8 و داکر و... بشین.

در این روش قراره از nodejs استفاده کنیم. البته نیازی نیست آشنایی زیادی با nodejs داشته باشید. در همین حد کافیه که روی سیستمون نصب کرده باشین تا بتونیم کدها رو باهاش اجرا کنیم. همین.

با nodejs همه چیز خوبه بجز گرفتن ورودی! چون تابع readline در nodejs وجود نداره. سایر روش‌های nodejs هم چندان خوب و جذاب نیستن برای همین می‌تونیم از روش ترکیبی که در پایین توضیح میدم استفاده کنیم.


اگر با سایت LeetCode آشنا باشین دیدین که برخلاف کوئرا، شما رو درگیر گرفتن ورودی و سایر کارهای اضافه نمیکنه. با توجه به زبانی که انتخاب می‌کنید برای شما یک تابع تعریف میکنه و صرفا از شما میخواد داخل تابع رو پیاده‌سازی کنید. مثلا برای حل مسئله Two Sum اگر زبان جاوااسکریپت رو انتخاب کنید فقط کافیه تابع زیر رو تکمیل کنید:

/** * @param {number[]} nums * @param {number} target * @return {number[]} */ var twoSum = function(nums, target) { };

اینکه کاربر رو درگیر گرفتن ورودی کنیم میتونه مزایا و معایب خودش رو داشته باشه. درکل ترجیح من خصوصا برای جاوااسکریپت این بود که کوئرا هم از همین روش استفاده میکرد تا درگیر V8 و... نشیم.

با الگوگیری از سایت LeetCode می‌تونیم یک تابع برای حل مسئله تعریف کنم تا روش گرفتن ورودی رو از روش حل مسئله جدا کنم.

مثلا فرض کنید می‌خوایم از کاربر یک اسم بگیریم و بهش سلام کنیم! در اینجا یک تابع نیاز داریم که یک اسم بگیره و سلام کنه! حالا اینکه ورودی رو چطوری گرفتیم بهش ربطی نداره. در یک مسئله ممکنه بخوایم اسم کاربر رو از صفحه کنسول بگیریم، در یک مسئله دیگه ممکنه بخوایم از فایل بخونیم یا از HTTP REST استفاده کنیم یا هر روش دیگه‌ای. درکل روش گرفتن ورودی ربطی به مسئله ما نداره. پس چرا تابع ما باید به تکنولوژی‌ها و روش‌های مختلف گرفتن ورودی وابسته باشه؟!

/** * @param {string} name */ function sayHello(name) { console.log(`Hello ${name}!`); } sayHello(&quotHamid&quot);

حالا که پیچیدگی حل مسئله رو از گرفتن ورودی جدا کردیم بیایین روی گرفتن ورودی تمرکز کنیم.

کوئرا از V8 استفاده میکنه. برای کوئرا باید از تابع readline استفاده کنیم ولی برای nodejs یه روش خوب و آسون اینه که ورودی‌ها رو به صورت دستی به تابع بدیم تا موقع دیباگ کردن برنامه راحت باشیم. دوتا راه داریم:

راه اول:

// UnComment this section for manual test // sayHello(&quotHamid&quot); //UnComment this section for Quera // sayHello(readline())

موقع دیباگ کردن می‌تونیم تیکه کد اول رو از حالت کامنت دربیاریم بعد که مسئله حل شد قسمت اول رو کامنت کنیم و قسمت دوم رو از کامنت دربیاریم. جواب میده ولی مشکلش اینه که اگر کد رو به کوئرا ارسال کنیم و خطا بخوریم مجبوریم این کار تکراری رو مدام انجام بدیم تا بالاخره جواب بده. طبیعتا کار خسته‌کننده‌ای هستش و از همه بدتر تکراری. برنامه‌نویس‌ها هم از کار تکراری متنفرن!

راه دوم: کاری کنیم که برنامه به صورت خودکار تشخیص بده از کدوم تیکه کد استفاده کنه. چطوری؟

اگر کد ما توسط nodejs اجرا بشه و V8 وجود نداشته باشه تابعی به نام readline هم وجود نداره. اگر از این تابع استفاده کنیم با خطای ReferenceError: readline is not defined مواجه میشیم که یعنی چنین تابعی تعریف نشده. اما اگر کد ما توسط سیستم داوری کوئرا (که V8 داره) اجرا بشه تابع readline وجود داره و تعریف شده.

پس فقط کافیه بررسی کنیم ببینیم آیا تابع readline تعریف شده یا نه. اگر تعریف شده بود می‌فهمیم که برنامه ما داره توسط V8 (کوئرا) اجرا میشه و اگر تعریف نشده بود می‌فهمیم که برنامه داره در سیستم لوکال ما که nodejs هستش و V8 نداره اجرا میشه. برای اینکار می‌تونیم از کد ساده زیر استفاده کنیم:

if (typeof readline === 'function') { // This is for Quera judge sayHello(readline()); } else { //This is for manual test sayHello(&quotHamid&quot); }

اینطوری با خیال راحت مسئله رو توی سیستم خودمون (و با IDE دلخواه) حل می‌کنیم بعدش بدون نیاز به تغییری، کد رو به کوئرا ارسال می‌کنیم تا توسط سیستم داوری تصحیح بشه. اگر خطا خورد هم کد مسئله رو تصحیح می‌کنیم و دوباره ارسال می‌کنیم بدون اینکه دغدغه داشته باشیم کد ما داره کجا اجرا میشه.


الان یه قالب حل مسئله خوب داریم که وقتی می‌خوایم مسئله جدیدی حل کنیم می‌تونیم ازش استفاده کنیم.

حالا بیایین کمی قالب حل مسئلمون رو تمیزتر کنیم.

هرچقدر مسئله پیچیده‌تر باشه برای خوانایی و تمیزی کد بهتره توابع مختلفی رو تعریف و استفاده کنیم. یه کار کوچیک و خوبی که می‌تونیم انجام بدیم اینه که مجموعه توابع مسئله رو با کلاس دسته‌بندی کنیم. می‌تونیم یه کلاس به نام Solution تعریف کنیم و تمامی توابع مربوط به حل مسئله رو اونجا تعریف کنیم تا کدهای مسئله ما از کدهای گرفتن ورودی جدا بشن و خوانایی و تمیزی کد ما بیشتر بشه. در اینصورت کد ما به صورت زیر میشه:

class Solution { /** * @param {string} name */ sayHello(name) { console.log(`Hello ${name}!`); } } let solution = new Solution(); if (typeof readline === 'function') { // This is for Quera judge solution.sayHello(readline()); } else { //This is for manual test solution.sayHello(&quotHamid&quot); }

جمله آخر

ترجیح خودم استفاده از روش اول (داکر) هستش. برای همین از این قالب استفاده می‌کنم اما اگر نمی‌خواین از داکر استفاده کنید می‌تونید از این قالب استفاده کنید.


مسائل مختلفی که از کوئرا حل می‌کنم رو توی این مخزن قرار میدم. اونجا می‌تونید راه‌حل‌های مختلف به زبان‌های پایتون، سی‌شارپ، جاوااسکریپت و ... رو ببینید. مسائل LeetCode رو هم در این مخزن قرار میدم. اگر دوست داشتین هم می‌تونید در این مخزن‌ها مشارکت کنید.

ان‌شاءالله موفق باشین :)

حل مسئلهکوئراجاوااسکریپتبرنامه نویسیداکر
یادداشت‌های شخصی درباره مهندسی نرم‌افزار، کسب و کار، فرهنگی و... به هدف رشد فردی و ان‌شاءالله مفید بودن. 🇵🇸️
شاید از این پست‌ها خوشتان بیاید