logo

Liukuikkunatekniikka

Liukuikkuna-ongelmat ovat ongelmia, joissa kiinteää tai muuttuvan kokoista ikkunaa siirretään tietorakenteen, tyypillisesti taulukon tai merkkijonon, läpi ongelmien ratkaisemiseksi tehokkaasti jatkuvien elementtien osajoukkojen perusteella. Tätä tekniikkaa käytetään, kun meidän on löydettävä aliryhmiä tai alijonoja tietyn ehtojoukon mukaisesti.

Liukuikkunatekniikka



Sisällysluettelo

Mikä on liukuikkunatekniikka?

Liukuikkunatekniikka on menetelmä, jota käytetään ratkaisemaan tehokkaasti ongelmia, joihin liittyy a ikkuna tai alue syöttötiedoissa (taulukoissa tai merkkijonoissa) ja siirtämällä ikkunaa tietojen poikki suorittaaksesi jonkin toiminnon ikkunassa. Tätä tekniikkaa käytetään yleisesti algoritmeissa, kuten tietyn summan omaavien alijonojen etsimisessä, pisimmän alimerkkijonon löytämisessä ainutlaatuisilla merkeillä tai ongelmien ratkaisemisessa, jotka edellyttävät kiinteän kokoista ikkunaa elementtien tehokkaaseen käsittelyyn.

Otetaan esimerkki tämän ymmärtämiseksi oikein, sanotaan, että meillä on erilaisia ​​kokoja N ja myös kokonaisluku K. Nyt meidän on laskettava koon omaavan alitaulukon maksimisumma K. Miten meidän pitäisi nyt lähestyä tätä ongelmaa?



Yksi tapa tehdä tämä ottamalla taulukosta jokainen K-koon alitaulukko ja selvittämällä näiden aliryhmien enimmäissumma. Tämä voidaan tehdä käyttämällä sisäkkäisiä silmukoita, jotka johtavat O(N2) Aika monimutkaisuus.

Mutta voimmeko optimoida tämän lähestymistavan?

Vastaus on kyllä, sen sijaan, että otat jokaisen K kokoinen alitaulukko ja laskemalla sen summa, voimme vain ottaa yhden K-koon alitaulukon 0:sta K-1-indeksiin ja laskea sen summan nyt siirtää aluettamme yksitellen iteraatioiden mukana ja päivittää tulosta, kuten seuraavassa iteraatiossa lisää vasenta ja oikea osoitin ja päivitä edellinen summa alla olevan kuvan mukaisesti:



Liukuikkunatekniikka

Noudata nyt tätä menetelmää jokaiselle iteraatiolle, kunnes saavutamme taulukon loppuun:

Liukuikkunatekniikka

javascript-operaattorit

Joten voimme nähdä, että sen sijaan, että laskemme kunkin K-kokoisen alitaulukon summan uudelleen, käytämme aiempaa K-koon ikkunaa ja sen tuloksia käyttämällä päivitämme summan ja siirrämme ikkunaa oikealle siirtämällä vasenta ja oikeaa osoitinta, tämä operaatio on optimaalinen, koska käytä O(1)-aikaa alueen siirtämiseen uudelleenlaskennan sijaan.

Tämä osoittimien siirtäminen ja tulosten laskeminen sen mukaisesti tunnetaan nimellä Liukuikkunan tekniikka .

Kuinka käyttää liukuikkunatekniikkaa?

Liukuikkunoita on periaatteessa kahdenlaisia:

1. Kiinteän kokoinen liukuikkuna:

Yleiset vaiheet näiden kysymysten ratkaisemiseksi seuraavilla vaiheilla:

  • Etsi haluamasi ikkunan koko, sano K.
  • Laske tulos 1. ikkunalle, eli sisällytä tietorakenteen ensimmäiset K elementtiä.
  • Liu'uta sitten ikkunaa yhdellä silmukalla ja jatka tuloksen laskemista ikkuna kerrallaan.

2. Muuttuvan koon liukuva ikkuna:

Yleiset vaiheet näiden kysymysten ratkaisemiseksi seuraavilla vaiheilla:

  • Tämän tyyppisessä liukuikkuna-ongelmassa lisäämme oikeaa osoitinta yksitellen, kunnes ehtomme on totta.
  • Missä tahansa vaiheessa, jos tilamme ei täsmää, pienennämme ikkunamme kokoa suurentamalla vasenta osoitinta.
  • Jälleen, kun tilamme on tyydyttävä, alamme kasvattaa oikeaa osoitinta ja noudatamme vaihetta 1.
  • Noudatamme näitä vaiheita, kunnes saavutamme taulukon loppuun.

Liukuikkunoiden ongelmien tunnistaminen:

  • Nämä ongelmat vaativat yleensä maksimi/minimi etsimistä Subarray , Alimerkkijonot jotka täyttävät tietyn ehdon.
  • alitaulukon tai alimerkkijonon koko ' K' annetaan joissakin ongelmissa.
  • Nämä ongelmat voidaan helposti ratkaista O(N2) aika monimutkaisuus käyttämällä sisäkkäisiä silmukoita, liukuvalla ikkunalla voimme ratkaista nämä Päällä) Aika monimutkaisuus.
  • Vaadittu aika monimutkaisuus: O(N) tai O(Nlog(N))
  • Rajoitukset: N <= 106, Jos N on taulukon/merkkijonon koko.

Liukuikkunatekniikan käyttötapaukset:

1. Löytääksesi kaikkien K-koon aliryhmien enimmäissumman:

Annettu joukko kokoisia kokonaislukuja 'n', Tavoitteemme on laskea maksimisumma 'k' peräkkäisiä elementtejä taulukossa.

Syöte: arr[] = {100, 200, 300, 400}, k = 2
Lähtö: 700

Syöte: arr[] = {1, 4, 2, 10, 23, 3, 1, 0, 20}, k = 4
Lähtö: 39
Saat maksimisumman lisäämällä alitaulukon {4, 2, 10, 23} koosta 4.

Syöte: arr[] = {2, 3}, k = 3
Lähtö: Virheellinen
Kokoa 3 ei ole, koska koko taulukon koko on 2.

Naiivi lähestymistapa: Joten analysoidaan ongelma Brute Force Approach . Aloitamme ensimmäisestä indeksistä ja summaamme arvoon asti kth elementti. Teemme sen kaikille mahdollisille peräkkäisille lohkoille tai k elementin ryhmille. Tämä menetelmä vaatii sisäkkäisen for-silmukan, ulompi for-silmukka alkaa k elementin lohkon aloituselementistä ja sisempi tai sisäkkäinen silmukka summautuu k:nneen elementtiin.

Alla on yllä olevan lähestymistavan toteutus:

C++
// O(n*k) solution for finding maximum sum of // a subarray of size k #include  using namespace std; // Returns maximum sum in a subarray of size k. int maxSum(int arr[], int n, int k) {  // Initialize result  int max_sum = INT_MIN;  // Consider all blocks starting with i.  for (int i = 0; i < n - k + 1; i++) {  int current_sum = 0;  for (int j = 0; j < k; j++)  current_sum = current_sum + arr[i + j];  // Update result if required.  max_sum = max(current_sum, max_sum);  }  return max_sum; } // Driver code int main() {  int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = sizeof(arr) / sizeof(arr[0]);  cout << maxSum(arr, n, k);  return 0; } // This code is contributed by Aditya Kumar (adityakumar129)>
C
// O(n*k) solution for finding maximum sum of // a subarray of size k #include  #include  #include  // Find maximum between two numbers. int max(int num1, int num2) {  return (num1>numero2) ? numero1 : numero2; } // Palauttaa maksimisumman alitaulukossa, jonka koko on k. int maxSum(int arr[], int n, int k) { // Alusta tulos int max_sum = INT_MIN;  // Tarkastellaan kaikkia i:llä alkavia lohkoja.  for (int i = 0; i< n - k + 1; i++) {  int current_sum = 0;  for (int j = 0; j < k; j++)  current_sum = current_sum + arr[i + j];  // Update result if required.  max_sum = max(current_sum, max_sum);  }  return max_sum; } // Driver code int main() {  int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = sizeof(arr) / sizeof(arr[0]);  printf('%d', maxSum(arr, n, k));  return 0; } // This code is contributed by Aditya Kumar (adityakumar129)>
Java
// Java code O(n*k) solution for finding maximum sum of // a subarray of size k class GFG {  // Returns maximum sum in  // a subarray of size k.  static int maxSum(int arr[], int n, int k)  {  // Initialize result  int max_sum = Integer.MIN_VALUE;  // Consider all blocks starting with i.  for (int i = 0; i < n - k + 1; i++) {  int current_sum = 0;  for (int j = 0; j < k; j++)  current_sum = current_sum + arr[i + j];  // Update result if required.  max_sum = Math.max(current_sum, max_sum);  }  return max_sum;  }  // Driver code  public static void main(String[] args)  {  int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = arr.length;  System.out.println(maxSum(arr, n, k));  } } // This code is contributed by Aditya Kumar (adityakumar129)>
Python 3
# code import sys # O(n * k) solution for finding # maximum sum of a subarray of size k INT_MIN = -sys.maxsize - 1 # Returns maximum sum in a # subarray of size k. def maxSum(arr, n, k): # Initialize result max_sum = INT_MIN # Consider all blocks # starting with i. for i in range(n - k + 1): current_sum = 0 for j in range(k): current_sum = current_sum + arr[i + j] # Update result if required. max_sum = max(current_sum, max_sum) return max_sum # Driver code arr = [1, 4, 2, 10, 2, 3, 1, 0, 20] k = 4 n = len(arr) print(maxSum(arr, n, k)) # This code is contributed by mits>
C#
// C# code here O(n*k) solution for // finding maximum sum of a subarray // of size k using System; class GFG {  // Returns maximum sum in a  // subarray of size k.  static int maxSum(int[] arr, int n, int k)  {  // Initialize result  int max_sum = int.MinValue;  // Consider all blocks starting  // with i.  for (int i = 0; i < n - k + 1; i++) {  int current_sum = 0;  for (int j = 0; j < k; j++)  current_sum = current_sum + arr[i + j];  // Update result if required.  max_sum = Math.Max(current_sum, max_sum);  }  return max_sum;  }  // Driver code  public static void Main()  {  int[] arr = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = arr.Length;  Console.WriteLine(maxSum(arr, n, k));  } } // This code is contributed by anuj_67.>
JavaScript
function maxSum(arr, n, k) {  let max_sum = 0;    // Loop from i to k  for (let i = 0; i < k; i++) {  max_sum += arr[i];  }    let window_sum = max_sum;  for (let i = k; i < n; i++) {  window_sum = window_sum - arr[i - k] + arr[i];  max_sum = Math.max(max_sum, window_sum);  }  return max_sum; } // Driver code let arr = [1, 4, 2, 10, 2, 3, 1, 0, 20]; let k = 4; let n = arr.length; console.log(maxSum(arr, n, k));>
PHP
 // code ?>// O(n*k) ratkaisu k-koon //-koon alitaulukon maksimisumman löytämiseen // Palauttaa maksimisumman k-koon alitaulukossa. funktio maxSum($arr, $n, $k) { // Alusta tulos $max_sum = PHP_INT_MIN ; // Tarkastellaan kaikkia lohkoja // alkaen kirjaimella i. for ( $i = 0; $i< $n - $k + 1; $i++) { $current_sum = 0; for ( $j = 0; $j < $k; $j++) $current_sum = $current_sum + $arr[$i + $j]; // Update result if required. $max_sum = max($current_sum, $max_sum ); } return $max_sum; } // Driver code $arr = array(1, 4, 2, 10, 2, 3, 1, 0, 20); $k = 4; $n = count($arr); echo maxSum($arr, $n, $k); // This code is contributed by anuj_67. ?>>>  
Lähtö Aika monimutkaisuus: O(k*n), koska se sisältää kaksi sisäkkäistä silmukkaa.
Aputila: O(1)

Liukuikkunatekniikan soveltaminen:

  • Laskemme ensimmäisen k elementin summan n termistä lineaarisen silmukan avulla ja tallennamme summan muuttujaan window_sum .
  • Sitten kuljemme lineaarisesti taulukon yli, kunnes se saavuttaa lopun, ja samalla seuraamme maksimisummaa.
  • Saadaksesi k-elementin lohkon nykyisen summan, vähennä ensimmäinen elementti edellisestä lohkosta ja lisää nykyisen lohkon viimeinen elementti.

Alla oleva esitys tekee selväksi, kuinka ikkuna liukuu taulukon yli.

Harkitse taulukkoa arr[] = {5, 2, -1, 0, 3} ja arvo k = 3 ja n = 5

Tämä on alkuvaihe, jossa olemme laskeneet alkuikkunan summan indeksistä 0 alkaen. Tässä vaiheessa ikkunan summa on 6. Nyt asetamme maksimisummaksi nykyinen_ikkuna eli 6.

Nyt liu'utamme ikkunaamme yksikköindeksin verran. Siksi se nyt hylkää 5 ikkunasta ja lisää 0:n ikkunaan. Näin ollen saamme uuden ikkunan summan vähentämällä 5 ja lisäämällä siihen 0. Joten ikkunasummamme tulee nyt 1. Nyt verrataan tätä ikkunasummaa maksimi_summaan. Koska se on pienempi, emme muuta enimmäissummaa.


Vastaavasti liu'utamme nyt jälleen ikkunaamme yksikköindeksin verran ja saamme uuden ikkunan summaksi 2. Tarkistamme jälleen, onko tämä nykyinen ikkunan summa suurempi kuin tähän asti maksimi_summa. Jälleen kerran se on pienempi, joten emme muuta enimmäissummaa.
Siksi yllä olevan taulukon maksimi_summa on 6.

Alla on koodi yllä olevalle lähestymistavalle:

paras hentai
C++
// O(n) solution for finding maximum sum of // a subarray of size k #include  using namespace std; // Returns maximum sum in a subarray of size k. int maxSum(int arr[], int n, int k) {  // n must be greater  if (n <= k) {  cout << 'Invalid';  return -1;  }  // Compute sum of first window of size k  int max_sum = 0;  for (int i = 0; i < k; i++)  max_sum += arr[i];  // Compute sums of remaining windows by  // removing first element of previous  // window and adding last element of  // current window.  int window_sum = max_sum;  for (int i = k; i < n; i++) {  window_sum += arr[i] - arr[i - k];  max_sum = max(max_sum, window_sum);  }  return max_sum; } // Driver code int main() {  int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = sizeof(arr) / sizeof(arr[0]);  cout << maxSum(arr, n, k);  return 0; }>
Java
// Java code for // O(n) solution for finding // maximum sum of a subarray // of size k class GFG {  // Returns maximum sum in  // a subarray of size k.  static int maxSum(int arr[], int n, int k)  {  // n must be greater  if (n <= k) {  System.out.println('Invalid');  return -1;  }  // Compute sum of first window of size k  int max_sum = 0;  for (int i = 0; i < k; i++)  max_sum += arr[i];  // Compute sums of remaining windows by  // removing first element of previous  // window and adding last element of  // current window.  int window_sum = max_sum;  for (int i = k; i < n; i++) {  window_sum += arr[i] - arr[i - k];  max_sum = Math.max(max_sum, window_sum);  }  return max_sum;  }  // Driver code  public static void main(String[] args)  {  int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = arr.length;  System.out.println(maxSum(arr, n, k));  } } // This code is contributed // by prerna saini.>
Python 3
# O(n) solution for finding # maximum sum of a subarray of size k def maxSum(arr, k): # length of the array n = len(arr) # n must be greater than k if n <= k: print('Invalid') return -1 # Compute sum of first window of size k window_sum = sum(arr[:k]) # first sum available max_sum = window_sum # Compute the sums of remaining windows by # removing first element of previous # window and adding last element of # the current window. for i in range(n - k): window_sum = window_sum - arr[i] + arr[i + k] max_sum = max(window_sum, max_sum) return max_sum # Driver code arr = [1, 4, 2, 10, 2, 3, 1, 0, 20] k = 4 print(maxSum(arr, k)) # This code is contributed by Kyle McClay>
C#
// C# code for O(n) solution for finding // maximum sum of a subarray of size k using System; class GFG {  // Returns maximum sum in  // a subarray of size k.  static int maxSum(int[] arr, int n, int k)  {  // n must be greater  if (n <= k) {  Console.WriteLine('Invalid');  return -1;  }  // Compute sum of first window of size k  int max_sum = 0;  for (int i = 0; i < k; i++)  max_sum += arr[i];  // Compute sums of remaining windows by  // removing first element of previous  // window and adding last element of  // current window.  int window_sum = max_sum;  for (int i = k; i < n; i++) {  window_sum += arr[i] - arr[i - k];  max_sum = Math.Max(max_sum, window_sum);  }  return max_sum;  }  // Driver code  public static void Main()  {  int[] arr = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };  int k = 4;  int n = arr.Length;  Console.WriteLine(maxSum(arr, n, k));  } } // This code is contributed by anuj_67.>
JavaScript
>>PHP>>  
Lähtö Aika monimutkaisuus: O(n), missä n on syöttötaulukon koko arr[] .
Aputila: O(1)

2. Pienin alitaulukko, jonka summa on suurempi kuin annettu arvo:

Annettu joukko arr[] kokonaislukuja ja lukuja X , tehtävänä on löytää pienin alitaulukko, jonka summa on suurempi kuin annettu arvo.

Lähestyä:

Voimme ratkaista tämän ongelman käyttämällä Sliding Window Technique -tekniikkaa ja ylläpitämällä kahta osoitinta: alku ja loppu merkitsemään ikkunan alkamista ja loppua. Voimme kasvattaa loppuosoitinta, kunnes ikkunan summa on pienempi tai yhtä suuri kuin X. Kun ikkunan summasta tulee suurempi kuin X, kirjataan ikkunan pituus ja aloitetaan siirtämällä aloitusosoitinta ikkunan summaan asti. muuttuu pienemmäksi tai yhtä suureksi kuin X. Nyt kun summasta tulee pienempi tai yhtä suuri kuin X, aloita taas lopetusosoittimen kasvattaminen. Jatka aloitus- ja loppuosoittimen siirtämistä, kunnes olemme saavuttaneet taulukon loppuun.

3. Etsi alitaulukko annetulla summalla ei-negatiivisten kokonaislukujen joukosta:

Annettu joukko arr[] ei-negatiivisista kokonaisluvuista ja kokonaisluvusta summa , etsi alitaulukko, joka lisää annettuun summa .

Lähestyä:

Idea on yksinkertainen, koska tiedämme, että kaikki alitaulukon elementit ovat positiivisia, joten jos alitaulukon summa on suurempi kuin annettu summa silloin ei ole mahdollista, että elementtien lisääminen nykyiseen alitaulukkoon on yhtä suuri kuin annettu summa. Ideana on siis käyttää samanlaista lähestymistapaa kuin a Liukuikkuna .

  • Aloita tyhjästä alaryhmästä.
  • lisää elementtejä alitaulukkoon, kunnes summa on pienempi kuin x ( annettu summa ) .
  • Jos summa on suurempi kuin x , poista elementit alkaa nykyisestä alaryhmästä.

4. Pienin ikkuna, joka sisältää kaikki itse merkkijonon merkit:

Lähestyä:

Periaatteessa merkkiikkunaa ylläpidetään käyttämällä kahta osoitinta alkaa ja loppu . Nämä alkaa ja loppu osoittimilla voidaan pienentää ja suurentaa ikkunaa vastaavasti. Aina kun ikkuna sisältää kaikki tietyn merkkijonon merkit, ikkunaa pienennetään vasemmalta puolelta ylimääräisten merkkien poistamiseksi ja sitten sen pituutta verrataan pienimpään tähän mennessä löydettyyn ikkunaan.
Jos nykyisessä ikkunassa ei voi poistaa enempää merkkejä, alamme kasvattaa ikkunan kokoa käyttämällä loppu kunnes kaikki merkkijonossa olevat erilliset merkit ovat myös ikkunassa. Etsi lopuksi kunkin ikkunan vähimmäiskoko.

Harjoittele ongelmia liukuikkunatekniikassa:

Ongelma

Ongelma Linkki

Etsi Subarray annetulla summalla

Ratkaista

Liukuva ikkuna maksimi (enintään kaikki K-koon alirivit)

Ratkaista

Pisin alitaulukko summalla K

Ratkaista

Etsi k-koon alitaulukon maksimi (tai pienin) summa

Ratkaista

Merkkijonon pienin ikkuna, joka sisältää kaikki toisen merkkijonon merkit

Ratkaista

Pisimmän osamerkkijonon pituus ilman toistuvia merkkejä

Ratkaista

Ensimmäinen negatiivinen kokonaisluku jokaisessa k-koon ikkunassa

Ratkaista

Laske erilliset elementit jokaisessa k-koon ikkunassa

Ratkaista

Pienin ikkuna, joka sisältää kaikki itse merkkijonon merkit

bool merkkijonoon java

Ratkaista

Suurin summaalitaulukko, jossa on vähintään k numeroa

Ratkaista

Aiheeseen liittyvät artikkelit:

  • R viimeisimpiä artikkeleita liukuikkunoiden tekniikasta
  • Harjoittele kysymyksiä liukuvasta ikkunasta
  • DSA Self-Paced – DSA:n eniten käytetty ja luotettu kurssi