Sonlar va matematika asoslari
Dasturlashda har qadamda matematika bor — ko'pincha sezilmagan holda. Indeks tekshiruvi, o'rtacha hisoblash, qoldiq topish, raqamlarni o'qish yoki ikki sonning eng katta umumiy bo'luvchisi. Bularning hammasi qandaydir matematik operatsiya.
DSA masalalarida matematika aloqida bir mavzu sifatida uchramaydi — u boshqa tuzilma va algoritmlarga singib ketgan. Lekin ayrim masalalar matematik mulohaza asosida yechiladi: array traversal emas, formulaga tayanish. Bunday masalalarda algoritmik yechim O(n) bo'lsa, matematik yechim O(1) yoki O(log n) berishi mumkin.
Bu maqolada dasturchi uchun amaliy matematik tushunchalar yig'ilgan: sonlarning kompyuterdagi ko'rinishi, bo'lish va qoldiq nozikliklari, raqamlar bilan ishlash, GCD/LCM, sodda sonlar, darajalar va tez-tez ishlatiluvchi formulalar.
Sonlar kompyuterda qanday saqlanadi?
O'zgarmas xotira o'lchami
Kompyuter xotirasida butun son o'zgaruvchisi — odatda 32 yoki 64 bit — qat'iy aniqlangan o'lchamga ega. Bu o'lcham saqlanishi mumkin bo'lgan qiymat oralig'ini belgilaydi.
32-bitli ishorasiz butun son:
32-bitli ishorali butun son (ikkilik to'ldiruvchi — two's complement):
64-bitli ishorali butun son:
Integer overflow
Qiymat maksimal chegaradan oshsa — overflow sodir bo'ladi. Natija kutilmagan bo'ladi:
DSA masalalarida overflow ehtimolini oldindan baholash muhim. Ikkita katta 32-bitli sonni ko'paytirishdan oldin 64-bitli o'zgaruvchiga o'tkazish yoki natijaning oralig'ini tekshirish kerak.
Overflow ni oldini olishning oddiy usuli — arifmetikani tekshirish:
// a + b overflow qiladimi (ishorali 32-bit uchun)?
// Agar a > 0 va b > INT_MAX - a bo'lsa — overflow
// Agar a < 0 va b < INT_MIN - a bo'lsa — overflow
To'ldiruvchi ikkilik (two's complement)
Salbiy sonlar kompyuterda to'ldiruvchi ikkilik usulida saqlanadi. Bu yondashuv qo'shish va ayirish uchun bir xil qurilmani ishlatish imkonini beradi.
-n ni topish uchun: n ning barcha bitlarini teskari qilib, 1 qo'shiladi:
Buni bilish bit manipulyatsiya masalalarida kerak bo'ladi.
Bo'lish va qoldiq
Butun son bo'lishi
Ikki butun sonni bo'lganda qoldiq ham mavjud bo'lishi mumkin:
Ko'p tillarda / operatori butun sonlar uchun natijani nol tomon qisqartiradi (truncation toward zero):
7 / 2 = 3 (matematikada ham 3)
-7 / 2 = -3 (matematikada -3.5, nol tomonga: -3)
7 / -2 = -3 (matematikada -3.5, nol tomonga: -3)
-7 / -2 = 3 (matematikada 3.5, nol tomonga: 3)
Ayrim tillarda yoki kutubxonalarda floor division (pastga qisqartirish) ishlatiladi:
Masalada "qaysi bo'lish" ishlatilayotganini aniqlamasdan natija farq qilishi mumkin.
Qoldiq (modulo)
Qoldiq operatori % bo'linuvchining belgisini oladi (ko'p tillarda):
7 % 3 = 1
-7 % 3 = -1 // ko'p tillarda -1, ba'zilarida 2
7 % -3 = 1 // ko'p tillarda 1, ba'zilarida -2
Matematikada qoldiq har doim manfiy bo'lmagan. Agar manfiy bo'lmagan qoldiq kerak bo'lsa:
Bu a manfiy bo'lsa ham to'g'ri manfiy bo'lmagan qoldiq beradi.
Foydali bo'lish va qoldiq iboralari
Sonning juft-toqligini tekshirish:
n ni k ga to'liq bo'linishini tekshirish:
Yuqori karralilikka yaxlitlash:
// n ni k ning yuqori karraligiga yaxlitlash (n > 0, k > 0)
yaxlit = ((n + k - 1) / k) * k
// yoki
yaxlit = k * CEILING(n / k)
Davriy (circular) indeks:
Ring buffer yoki aylana massivda:
Raqamlarni qayta ishlash
Oxirgi raqamni olish
Sonning o'nlik sanoqdagi oxirgi raqami % 10:
Oxirgi raqamni kesib tashlash
/ 10 sonning oxirgi raqamini olib tashlaydi:
Raqamlar sonini hisoblash
FUNCTION DIGIT_COUNT(n)
IF n = 0
RETURN 1
count = 0
n = ABS(n) // manfiy son uchun
WHILE n > 0
count = count + 1
n = n / 10
RETURN count
Muqobil: FLOOR(LOG10(n)) + 1 (n > 0 uchun). Lekin floating-point aniqsizligi sababli raqamlar soni katta bo'lsa ehtiyot bo'lish kerak.
Raqamlarni sanab chiqish
FUNCTION GET_DIGITS(n)
n = ABS(n)
digits = bo'sh list
IF n = 0
RETURN [0]
WHILE n > 0
digits ga n % 10 ni qo'sh
n = n / 10
RETURN digits teskari tartibda // oxiridan oldingiga
GCD va LCM
Eng katta umumiy bo'luvchi (GCD)
GCD (greatest common divisor) — ikki sonning eng katta umumiy bo'luvchisi. Kasr qisqartirishda, LCM hisoblashda, ba'zan "bir xil o'lcham" topishda kerak.
Evklid algoritmi:
Nima uchun ishlaydi? Evklid isbotlagan: GCD(a, b) = GCD(b, a % b). b nolga yetganda — a javob.
Murakkablik: O(log(min(a, b))) — har qadam b kamida ikki barobarga kichrayadi.
Rekursiv ko'rinishi:
Eng kichik umumiy karrali (LCM)
LCM (least common multiple) — ikki sonning eng kichik umumiy karrali. GCD orqali:
Nima uchun avval bo'linadi? a * b overflow qilishi mumkin. a / GCD(a, b) natijasi doim butun son.
Sodda sonlar (prime numbers)
Ta'rif
Sodda son (prime) — faqat 1 va o'ziga bo'linadigan 1 dan katta butun son. Eng kichik sodda sonlar: 2, 3, 5, 7, 11, 13...
Bitta sonni tekshirish
Naiv yondashuv: 2 dan n-1 gacha tekshirish — O(n).
Yaxshilangan: sqrt(n) gacha tekshirish yetarli, chunki agar n = a × b bo'lsa, a va b ning biri sqrt(n) dan kichik yoki teng:
FUNCTION IS_PRIME(n)
IF n < 2
RETURN FALSE
IF n = 2
RETURN TRUE
IF n % 2 = 0
RETURN FALSE
i = 3
WHILE i * i ≤ n
IF n % i = 0
RETURN FALSE
i = i + 2 // faqat toq sonlar
RETURN TRUE
Murakkablik: O(sqrt(n)).
Eratosfen g'alviri (Sieve of Eratosthenes)
n gacha bo'lgan barcha sodda sonlarni topish uchun:
FUNCTION SIEVE(n)
is_prime = n + 1 ta TRUE qiymatdan iborat array
is_prime[0] = FALSE
is_prime[1] = FALSE
i = 2
WHILE i * i ≤ n
IF is_prime[i] = TRUE
j = i * i
WHILE j ≤ n
is_prime[j] = FALSE
j = j + i
i = i + 1
primes = bo'sh list
FOR i = 2 DAN n GACHA
IF is_prime[i] = TRUE
primes ga i ni qo'sh
RETURN primes
Nima uchun i * i dan boshlanadi? i ning 2 dan i-1 gacha barcha karrali bo'linuvchilari avvalgi iteratsiyalarda allaqachon belgilangan. Masalan, i=5 da 5×2, 5×3, 5×4 lar allaqachon belgilangan.
Murakkablik: O(n log log n) vaqt, O(n) xotira.
Darajalar va logarifmlar
Ikkilik daraja (power of 2)
2^k sonlari DSAda tez-tez uchraydi: xotira o'lchamlari, bitlarning soni, binary tree sathlari soni.
nning ikki darajasi ekanligini tekshirish:
Nima uchun? 2^k binarda bitta 1 bit va qolgan 0 bitlar. 2^k - 1 esa shu bitning o'rnidan pastdagi barcha bitlar 1. AND qilinganda natija 0:
Logarifm
log₂(n) — n ni ikkilik bo'lish uchun necha qadam:
Binary search, balanced BST, heap kabi tuzilmalar O(log n) murakkablik beradi aynan shu sababdan: har qadam ma'lumot hajmini yarmiga kamaytiradi.
Bu son n ning ikkilik ko'rinishidagi eng yuqori 1 bitning o'rnidir.
Foydali formulalar
Birinchi n natural son yig'indisi
Bu formulani bilish "aylana ro'yxatdagi barcha juftliklar yig'indisi" yoki "nechta iteratsiya" kabi masalalarda O(n) tsiklni O(1) ga almashtiradi.
Birinchi n kvadrat yig'indisi
Geometrik ketma-ketlik yig'indisi
r = 2 uchun:
Bu daraxtlardagi tugunlar soni yoki bit hiylalarida uchraydi.
XOR xossalari
Bu xossalar "takrorsiz element" masalalarida ishlatiladigan XOR usulining asosi.
Modulyar arifmetika
Modulyar arifmetika — sonlarni ma'lum bir modulga nisbatan hisoblash. n mod m — n ni m ga bo'lgandagi qoldiq.
Katta son hisoblashda modulga nisbatan arifmetika:
(a + b) mod m = ((a mod m) + (b mod m)) mod m
(a × b) mod m = ((a mod m) × (b mod m)) mod m
(a - b) mod m = ((a mod m) - (b mod m) + m) mod m
Nima uchun kerak? Kriptografiya, hash hisoblash, "nechta yo'l bor?" masalalarida javob ibtidoiy katta son bo'ladi. 10^9 + 7 kabi katta tub son moduliga hisoblash overflow'ni oldini oladi.
Note
(a / b) mod m bu qoidaga mos kelmaydi — bu uchun modulyar teskari element (modular inverse) kerak. Oddiy (a mod m) / (b mod m) to'g'ri emas.
Keng tarqalgan masala patternlari
Raqamlarni aylanib chiqish
Sonni raqamlarga ajratib tekshirish yoki o'zgartirish:
Hisob-kitob overflow qilmasligini ta'minlash
Ikki katta son ko'paytmasini hisoblashdan oldin:
Yoki kattaroq tip ishlatish.
Binary exponentiation (tez daraja hisoblash)
a^n ni naiv usulda O(n) ko'paytma, tez usulda O(log n):
FUNCTION FAST_POW(base, exp)
result = 1
WHILE exp > 0
IF exp % 2 = 1
result = result * base
base = base * base
exp = exp / 2
RETURN result
G'oya: a^8 = (a^4)^2 = ((a^2)^2)^2 — darajani har ikkilashda hisoblar soni log2 bo'yicha kamayadi.
Prefix sum (oldingi yig'indilar)
Diapazon so'rovlari uchun:
prefix[0] = 0
prefix[i] = prefix[i-1] + array[i-1]
// [l, r] diapazoni yig'indisi:
sum = prefix[r+1] - prefix[l]
Bu O(n) preprocessingdan keyin har so'rovni O(1) ga tushiradi.
Keng tarqalgan xatolar
Nolga bo'lish. Bo'linuvchi nol bo'lishi mumkin bo'lgan holatlarni avval tekshirish kerak.
Integer overflow. Ikkita katta sonni ko'paytirishdan oldin natijaning oralig'ini baholash. GCD, faktorial, kombinatorika hisoblashda tez-tez uchraydi.
Manfiy sonlarda qoldiq. % operatori tizimga qarab manfiy natija berishi mumkin. Manfiy bo'lmagan qoldiq kerak bo'lsa ((a % m) + m) % m ishlatish.
Floating-point arifmetikasi. sqrt(n) yoki log(n) hisoblashda floating-point yaxlitlash xatosi bo'lishi mumkin. sqrt(n) orqali sodda son tekshirishda (int)sqrt(n) ni i * i <= n sharti bilan almashtirish xavfsizroq.
Sifr (0) xolatlari. n = 0 ko'p formulani buzadi: log(0) aniqlanmagan, 0! alohida holat, GCD(0, n) = n deb belgilangan.
Qachon matematik yondashuv kerak?
- Javob bir formula bilan hisoplanishi mumkin bo'lsa (
O(1)) - Elementlar orasidagi bog'liqlik matematik xossa bo'lsa (xor, yig'indi, ko'paytma)
- Katta sonlar moduliga hisoblash kerak bo'lsa
- Takroriy hisoblashni kamaytirish uchun prefix sum kerak bo'lsa
- Sodda son tekshirish yoki GCD/LCM kerak bo'lsa
Matematik yondashuv doim to'g'ri emas: ba'zan murakkab formula ishlatgandan ko'ra, sodda traversal bilan yechim xatosizroq. Formula tanlanganda uning chegaralari (salbiy son, nol, overflow) tekshiriladi.
Xulosa
Sonlar va matematik operatsiyalar DSAda ko'rinmas poydevor. Integer overflow, bo'lish qoidalari, raqamlarni ajratish, GCD, sodda son tekshirish — bularning hammasi masalalarda birdaniga paydo bo'ladi.
Eng muhim narsalar:
- 32-bitli ishorali sonning chegarasi:
±2 147 483 647 - Manfiy qoldiq:
((a % m) + m) % m - GCD Evklid algoritmi:
O(log(min(a, b))) - Sodda son tekshirish:
sqrt(n)gacha - Birinchi
nson yig'indisi:n(n+1)/2 - Ikki darajasi tekshirish:
n & (n-1) = 0 - Tez daraja:
O(log n)
Keyingi mavzularda shu asoslardan foydalanadigan masalalar ko'riladi.