Մարտահրավերի նկարագրություն
Հաշվի առնելով nums
զանգվածը՝ n
, վերադարձրեք մեծամասնության տարրը:
Մեծամասնության տարրը այն տարրն է, որը հայտնվում է ավելի քան ⌊n / 2⌋
անգամ: Դուք կարող եք ենթադրել, որ մեծամասնության տարրը միշտ գոյություն ունի զանգվածում:
Օրինակ 1
Input: nums = [3,2,3] Output: 3
Օրինակ 2
Input: nums = [2,2,1,1,1,2,2] Output: 2
Մոտեցում 1. Տեսակավորում
Ինտուիցիա՝
Այս մոտեցման հիմքում ընկած ինտուիցիան այն է, որ եթե տարրը զանգվածում հայտնվում է ավելի քան n/2 անգամ (որտեղ n-ը զանգվածի չափն է), այն միշտ կզբաղեցնի միջին դիրքը, երբ զանգվածը տեսակավորվում է: Հետևաբար, մենք կարող ենք տեսակավորել զանգվածը և տարրը վերադարձնել n/2 ինդեքսում։
Բացատրություն.
- Կոդը սկսվում է
nums
զանգվածը չնվազող կարգով դասավորելով՝ օգտագործելով Typescript ստանդարտ գրադարանիsort
ֆունկցիան: Սա վերադասավորում է տարրերն այնպես, որ նույնական տարրերը խմբավորվեն միասին: - Զանգվածը տեսակավորելուց հետո մեծամասնության տարրը միշտ ներկա կլինի
n/2
ինդեքսում, որտեղn
զանգվածի չափն է:
- Դա պայմանավորված է նրանով, որ մեծամասնության տարրը հանդիպում է ավելի քան n/2 անգամ, և երբ զանգվածը տեսակավորվում է, այն կզբաղեցնի միջին դիրքը։
3. Կոդը վերադարձնում է n/2
ինդեքսում գտնվող տարրը որպես մեծամասնության տարր:
Այս մոտեցման ժամանակային բարդությունը O(n log n) է, քանի որ n չափի զանգվածի տեսակավորումը պահանջում է O(n log n) ժամանակ:
function majorityElement(nums: number[]): number { nums.sort((a, b) => a - b); // Sort the array in ascending order const n: number = nums.length; return nums[Math.floor(n / 2)]; }
Մոտեցում 2. Հեշ քարտեզ
Ինտուիցիա.
Հեշ-քարտեզ օգտագործելու հիմքում ընկած ինտուիցիան զանգվածի յուրաքանչյուր տարրի դեպքերը հաշվելն է և այնուհետև բացահայտել այն տարրը, որը հանդիպում է ավելի քան n/2 անգամ: Հաշիվները պահելով հեշ քարտեզում, մենք կարող ենք արդյունավետ կերպով հետևել յուրաքանչյուր տարրի երևույթներին:
Բացատրություն.
Իհարկե, եկեք բաժանենք TypeScript ֆունկցիան majorityElement(nums: number[]): number | null
քայլ առ քայլ.
const n: number = nums.length;
. Այս տողը հայտարարում էn
հաստատուն, որը պահպանում էnums
մուտքային զանգվածի երկարությունը, որը ներկայացնում է զանգվածի տարրերի ընդհանուր թիվը:const occurrences: Map<number, number> = new Map();
. Այս տողը սկզբնավորում է դատարկ քարտեզը, որը կոչվում էoccurrences
: Այս Քարտեզում ստեղները թվեր են (տարրերnums
զանգվածից), իսկ արժեքները՝ դրանց համապատասխան երևույթները կամ հաշվումները:for (let i = 0; i < n; i++) { ... }
. Այս օղակը կրկնվում էnums
զանգվածի յուրաքանչյուր տարրի միջով:const num = nums[i];
: Շրջանակի ներսում մենք հանում ենք զանգվածի ընթացիկ տարրը և այն պահումnum
փոփոխականում:occurrences.set(num, (occurrences.get(num) || 0) + 1);
. Այս տողը հաշվում էnums
զանգվածում յուրաքանչյուր տարրի առաջացումը՝ օգտագործելովoccurrences
Քարտեզը: Եթե num
տարրն արդեն առկա է Քարտեզում, մենք առբերում ենք դրա ընթացիկ թիվը (օգտագործելովoccurrences.get(num)
), կամ եթե այն չկա (այսինքն՝ տարրն առաջին անգամ է հանդիպում), մենք օգտագործում ենք0
: Այնուհետև մենք ավելացնում ենք հաշվարկը 1-ով և այն նորից պահում Քարտեզում:const threshold: number = n / 2;
: Այստեղ մենք հաշվարկում ենք շեմային արժեքը՝n
զանգվածի տարրերի ընդհանուր թիվը բաժանելով 2-ի: .for (const [key, value] of occurrences.entries()) { ... }
. Այս օղակը կրկնվում էoccurrences
Քարտեզի յուրաքանչյուր մուտքի (բանալին-արժեք զույգ) միջով:if (value > threshold) { ... }
. Օղակի ներսում մենք ստուգում ենք, արդյոքvalue
ընթացիկ տարրի հաշվարկը մեծ է շեմային արժեքից: Եթե այդպես է, ապա ներկայիսkey
տարրը զանգվածի մեծամասնության տարրն է: Մենք անմիջապես վերադարձնում ենք այս տարրը որպես արդյունք:- Եթե հանգույցն ավարտվում է առանց մեծամասնության տարր գտնելու, մենք հասնում ենք
return null; // No majority element found
տողին, ինչը նշանակում է, որ զանգվածում մեծամասնության տարր չկա: Նման դեպքերում ֆունկցիան վերադարձնում էnull
:
function majorityElement(nums: number[]): number | null { const n: number = nums.length; const occurrences: Map<number, number> = new Map(); for (let i = 0; i < n; i++) { const num = nums[i]; occurrences.set(num, (occurrences.get(num) || 0) + 1); } const threshold: number = n / 2; for (const [key, value] of occurrences.entries()) { if (value > threshold) { return key; } } return null; // No majority element found }
Մոտեցում 3. Մուրի քվեարկության ալգորիթմ
Ինտուիցիա՝
Մուրի քվեարկության ալգորիթմի հիմքում ընկած ինտուիցիան հիմնված է այն փաստի վրա, որ եթե զանգվածում կա մեծամասնության տարր, այն միշտ կմնա առաջատարի դիրքում, նույնիսկ այլ տարրերի հետ հանդիպելուց հետո:
Բացատրություն.
Ալգորիթմ՝
- Նախաձեռնեք երկու փոփոխական՝
count
ևcandidate
: Սահմանեքcount
-ը 0-ի, իսկcandidate
-ը՝ կամայական արժեքի: - Կրկնել
nums
զանգվածի միջով:
ա. Եթե count
-ը 0 է, ապա նշանակեք ընթացիկ տարրը որպես նորcandidate
և ավելացրեքcount
1-ով:
բ. Եթե ընթացիկ տարրը նույնն է, ինչcandidate
-ը, ավելացրեքcount
1-ով:
գ. Եթե ընթացիկ տարրը տարբերվում էcandidate
-ից, ապաcount
-ը նվազեցրեք 1-ով: - Կրկնելուց հետո
candidate
փոփոխականը կպահի մեծամասնության տարրը:
Բացատրություն.
- Ալգորիթմը սկսվում է առաջին տարրը որպես մեծամասնական թեկնածու ընդունելով և հաշվարկը սահմանում է 1-ի:
- Երբ այն կրկնվում է զանգվածի միջով, այն համեմատում է յուրաքանչյուր տարր թեկնածուի հետ.
a. Եթե ներկայիս տարրը համընկնում է թեկնածուի հետ, դա առաջարկում է, որ այն ամրապնդի մեծամասնության տարրը, քանի որ այն նորից հայտնվում է: Հետևաբար, հաշվարկն ավելանում է 1-ով:
բ. Եթե ներկայիս տարրը տարբերվում է թեկնածուից, ապա դա հուշում է, որ մեծամասնության տարրի և այլ տարրերի դեպքերը կարող են հավասար թվով լինել: Այսպիսով, հաշվարկը նվազում է 1-ով:
- Նկատի ունեցեք, որ քանակի նվազումը չի փոխում այն փաստը, որ մեծամասնության տարրը տեղի է ունենում ավելի քան n/2 անգամ:
3. Եթե հաշվարկը դառնում է 0, նշանակում է, որ ներկայիս թեկնածուն այլևս մեծամասնության պոտենցիալ տարր չէ: Այս դեպքում մնացած տարրերից ընտրվում է նոր թեկնածու։
4. Ալգորիթմը շարունակում է այս գործընթացը այնքան ժամանակ, քանի դեռ չի անցել ամբողջ զանգվածը:
5. candidate
փոփոխականի վերջնական արժեքը կպահի մեծամասնության տարրը:
Ճշտության բացատրություն.
Ալգորիթմն աշխատում է այն ենթադրության հիման վրա, որ մեծամասնության տարրը զանգվածում հանդիպում է ավելի քան n/2 անգամ: Այս ենթադրությունը երաշխավորում է, որ նույնիսկ եթե այլ տարրերի կողմից հաշվարկը զրոյացվի 0-ի, մեծամասնության տարրը ի վերջո կվերականգնի առաջատարը:
Դիտարկենք երկու դեպք.
- Եթե մեծամասնության տարրն ունի n/2-ից ավելի դեպքեր.
- Ալգորիթմը կապահովի, որ հաշվարկը դրական մնա մեծամասնության տարրի համար ողջ անցման ընթացքում՝ երաշխավորելով, որ այն կընտրվի որպես վերջնական թեկնածու:
2. Եթե մեծամասնության տարրը ունի ճշգրիտ n/2 երևույթ.
- Այս դեպքում մեծամասնության տարրի և մնացած տարրերի համար կլինեն հավասար թվով երևույթներ:
- Այնուամենայնիվ, մեծամասնության տարրը դեռ կընտրվի որպես վերջնական թեկնածու, քանի որ այն միշտ առաջատար է լինելու ցանկացած այլ տարրի նկատմամբ:
Երկու դեպքում էլ ալգորիթմը ճիշտ կբացահայտի մեծամասնության տարրը:
Մուրի քվեարկության ալգորիթմի ժամանակային բարդությունը O(n) է, քանի որ այն մեկ անգամ անցնում է զանգվածը:
Այս մոտեցումը արդյունավետ է տեսակավորման համեմատ, քանի որ այն պահանջում է միայն մեկ անցում զանգվածի միջով և չի փոխում տարրերի սկզբնական կարգը:
function majorityElement(nums: number[]): number | null { let count: number = 0; let candidate: number = 0; for (const num of nums) { if (count === 0) { candidate = num; } if (num === candidate) { count++; } else { count--; } } // Now, 'candidate' contains the potential majority element. // Check if it appears more than n/2 times to ensure it's the majority element. count = 0; for (const num of nums) { if (num === candidate) { count++; } } return count > nums.length / 2 ? candidate : null; }