Teknologian jakaminen

Algoritmi: Merkkijonoon liittyvä

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Sisällysluettelo

Aihe 1: Pisin yhteinen etuliite

Kysymys 2: Pisin palindromimerkkijono

Aihe 3: Binäärisumma

Kysymys 4: merkkijonojen kertominen


Aihe yksi:pisin yhteinen etuliite

Kirjoita funktio löytääksesi pisin yhteinen etuliite merkkijonojoukosta

Jos yhteistä etuliitettä ei ole, palauttaa tyhjän merkkijonon""

Esimerkki 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

Esimerkki 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

vihje:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i]Sisältää vain pieniä englanninkielisiä kirjaimia

Ratkaisu 1: Parivertailu

Ensimmäinen ratkaisu on parivertailu. Vertaa ensin kahden ensimmäisen merkkijonon yhteistä etuliitettä kolmanteen merkkijonoon, ja niin edelleen

koodi näytetään alla:

  1. class Solution
  2. {
  3. public:
  4. string findCommon(string& s1, string& s2)
  5. {
  6. int i = 0;
  7. //i有可能会出现越界的情况,所以i小于s1s2长度时再循环判断
  8. while(i < min(s1.size(), s2.size()) && s1[i] == s2[i])
  9. i++;
  10. return s1.substr(0, i);
  11. }
  12. string longestCommonPrefix(vector<string>& strs)
  13. {
  14. int n = strs.size();
  15. //same字符串就是存储最长公共前缀的字符串
  16. string same = strs[0];
  17. for(int i = 1; i < n; i++)
  18. same = findCommon(same, strs[i]);
  19. return same;
  20. }
  21. };

Ratkaisu 2: Yhtenäinen vertailu

Yhtenäinen vertailu tarkoittaa kaikkien merkkijonojen saman sijainnin vertaamista kerralla sen määrittämiseksi, ovatko paikat samat, kunnes eri merkit ilmestyvät.

Tässä on rajojen ulkopuolella oleva tilanne.

koodi näytetään alla:

  1. class Solution
  2. {
  3. public:
  4. string longestCommonPrefix(vector<string>& strs)
  5. {
  6. int i = 0;
  7. //以第一个字符串为基准,与其他所有字符串做比较
  8. for(i = 0; i < strs[0].size(); i++)
  9. {
  10. //ch表示第一个字符串当前循环到的字符
  11. char ch = strs[0][i];
  12. //循环strs中其余的字符串,其余字符串的i位置字符与ch做比较
  13. for(int j = 1; j < strs.size(); j++)
  14. {
  15. //如果i大于当前字符串的长度,说明当前字符串已经没有元素了
  16. if(i > strs[j].size() || strs[j][i] != ch)
  17. return strs[0].substr(0, i);
  18. }
  19. }
  20. return strs[0];
  21. }
  22. };

Aihe 2:pisin palindromimerkkijono

Anna merkkijonos, nosta ylössPisin palindromi-osamerkkijono

Esimerkki 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

Esimerkki 2:

输入:s = "cbbd"
输出:"bb"

Tavallinen raa'an voiman laskenta-algoritmi asettaa kaksi osoitinta, yksi i ja yksi j, korjaa i ja siirtää j:tä taaksepäin Joka kerta kun j:tä siirretään, on tarpeen määrittää, onko merkkijono i:n ja j:n välillä palindromimerkkijono. j on siirretty. Ja päätettäessä, onko i:n ja j:n välillä palindromiosamerkkijono, aikamonimutkaisuus tässä on O(N^2), ja koska ulkopuolella on sisäkkäinen i-kerros, jota käytetään koko merkkijonon läpi kulkemiseen. koko väkivaltainen luettelointiaika Monimutkaisuus on erittäin korkea, saavuttaen O(N^3). Katsotaanpa optimoitua keskustan laajennusalgoritmia:

Ratkaisu: Keskitä laajennusalgoritmi

Keskuksen laajennusalgoritmi on:

①Korjaa keskipiste
②Aloita keskipisteestä ja laajenna molemmille puolille (sekä parittomat että parilliset pituudet on otettava huomioon)

Toisin sanoen keskipiste i kiinnitetään joka kerta, ja joka kerta, kun sitä laajennetaan i:n vasemmalle ja oikealle puolelle sen määrittämiseksi, onko se palindromimerkkijono. Tämän i:n läpi kulkevan algoritmin aikamonimutkaisuus on O(N), ja sisäkkäinen suunta on i:n vasemmalle ja oikealle Laajennuksena myös aikakompleksisuus on O(N), joten se on lopulta O(N^2), mikä on paljon optimoitumpi kuin edellä mainittu väkivaltainen ratkaisu. .

Huomioittava on keskialueen laajennusalgoritmin toinen piste. Parittomat ja parilliset luvut siirtävät vasenta ja oikeaa osoittimia i-asemasta vasemmalle ja oikealle, kun taas parilliset luvut vaativat. vasen ollaksesi i-asennossa ja oikea olla kohdassa i + 1. ja sitten liikkua vasemmalle ja oikealle

On huomattava, että koodin pituus on oikea - vasen - 1, koska jos nykyinen vasen ja oikea osoittavat samaan elementtiin, sinun on vaihdettava vasen--, oikea++, jos ne eivät ole samat, poistu silmukasta , joten vasemmalla ja oikealla on enemmän kuin palindromimerkkijonoja. Se on siirtynyt yhden sijainnin, joten pituus lasketaan oikealta - vasemmalta - 1. Katso lisätietoja alla olevasta kuvasta.

Kuten yllä olevasta kuvasta näkyy, vasen ja oikea osoittavat nykyiseen pisteeseen poistuaksesi silmukasta, joten palindromi-alijonon aa pituus on:
oikea - vasen - 1 = 3 - 0 - 1 = 2


koodi näytetään alla:

  1. class Solution
  2. {
  3. public:
  4. string longestPalindrome(string s)
  5. {
  6. if(s.size() == 1) return s;
  7. int n = s.size(), begin = 0, size = 0;
  8. for(int i = 0; i < n; i++)
  9. {
  10. //先做奇数长度的扩展
  11. int left = i, right = i;
  12. //left和right符合条件,且指向元素相等再进入循环
  13. while(left >= 0 && right < n && s[left] == s[right])
  14. {
  15. --left;
  16. ++right;
  17. }
  18. //如果长度更大,更新begin与size
  19. if((right - left - 1) > size)
  20. {
  21. size = right - left - 1;
  22. begin = left + 1;
  23. }
  24. //再做偶数长度的扩展
  25. left = i, right = i + 1;
  26. //left和right符合条件,且指向元素相等再进入循环
  27. while(left >= 0 && right < n && s[left] == s[right])
  28. {
  29. --left;
  30. ++right;
  31. }
  32. //如果长度更大,更新begin与size
  33. if((right - left - 1) > size)
  34. {
  35. size = right - left - 1;
  36. begin = left + 1;
  37. }
  38. }
  39. return s.substr(begin, size);
  40. }
  41. };

Aihe kolme:Binäärisumma

Anna kaksi binäärimerkkijonoaajab, palauttavat summansa binäärimerkkijonona.

Esimerkki 1:

输入:a = "11", b = "1"
输出:"100"

Esimerkki 2:

输入:a = "1010", b = "1011"
输出:"10101"

Tämä kysymys koskee suuren tarkkuuden laskemista, simulointioperaation suorittamista ja pystysuoran laskennan simulointia.

Sinun on asetettava kaksi osoitinta, cur1 ja cur2, osoittamaan vastaavasti kahteen merkkijonoon, ja asetettava sitten muuttuja t edustamaan siirtoa.

koodi näytetään alla:

  1. class Solution
  2. {
  3. public:
  4. string addBinary(string a, string b)
  5. {
  6. //t表示相加后的进位
  7. int t = 0;
  8. string ret;
  9. int cur1 = a.size()-1, cur2 = b.size()-1;
  10. //cur1或cur2 >= 0表示字符串没遍历完,t>0表示还剩一个进位
  11. while(cur1 >= 0 || cur2 >= 0 || t)
  12. {
  13. if(cur1 >= 0) t += a[cur1--] - '0';
  14. if(cur2 >= 0) t += b[cur2--] - '0';
  15. ret += to_string(t % 2);
  16. t /= 2;
  17. }
  18. //从后向前加的,刚好反过来了,需要逆置
  19. reverse(ret.begin(), ret.end());
  20. return ret;
  21. }
  22. };

Aihe neljä:Merkkijonojen kertolasku

Annettu kaksi ei-negatiivista kokonaislukua, jotka esitetään merkkijonoinanum1janum2,palatanum1janum2Tuotteen , heidän tuotteensa ilmaistaan ​​myös merkkijonomuodossa.

Ilmoitus:Et voi käyttää mitään sisäänrakennettuja BigInteger-kirjastoja tai muuntaa syötettä suoraan kokonaisluvuksi.

Esimerkki 1:

输入: num1 = "2", num2 = "3"
输出: "6"

Esimerkki 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

Ratkaisu 1: Simuloi pystysuorat toiminnot

Matematiikassa se on kertolasarakkeen pystymuoto. Tämä on helpoin tapa ajatella.

Seuraavasti:

Ymmärrämme sen siten, että jokainen seuraavan 456:n numero kerrotaan yllä olevalla 123:lla ja lisätään sitten kolme yksityiskohtaa:

①Korkeamman asteen kertolasku on täytettävä 0:lla, koska yksi bitti on väärin lisättäessä 738 ja 615, jotka voidaan ymmärtää 738 + 6150
②Prosessin alku 0, tilanne on 123 × 0, jolloin vastaus on 000 ja se on käsiteltävä.
③ Kiinnitä huomiota laskentatulosten järjestykseen, koska laskenta suoritetaan käänteisessä järjestyksessä ja kertolasku lasketaan viimeisestä numerosta.

Mutta tämä menetelmä ei ole helppo kirjoittaa koodia. Meidän on käytettävä tätä menetelmää sen optimoimiseksi.

Ratkaisu kaksi: Optimoi Ratkaisu Yksi

Kerro ja lisää ilman siirtoa, ja siirto käsitellään viimeisessä vaiheessa:

Eli riippumatta siitä, kuinka paljon kerrotaan, siirtoa ei tule, ja siirto suoritetaan viimeisen lisäyksen jälkeen.

Samoin, kun aloitat laskennan, käännä järjestys, koska kertolasku voi olla kaksinumeroinen, merkkijonoesitystä ei voi käyttää sen sijaan

Koska järjestys on käänteinen, 123:a vastaava alaindeksi on 2,1,0 ja 456 vastaava alaindeksi on myös 2,1,0

On olemassa erittäin hyödyllinen sääntö: i:llä ja j:llä merkityt luvut kerrotaan, ja tulos sattuu olemaan taulukon i + j:nneksi.

① Määrittele taulukko tmp, jonka pituus on m + n - 1 (m ja n vastaavat kahden kerrotun luvun pituuksia)
Kahden kerrottavan luvun alaindeksit ovat i ja j, vastaavasti, ja laskettu tulos sijoitetaan taulukon i + j:nnelle paikalle.
② Viimeisen lisäyksen jälkeen kanto on käsiteltävä
③ Käsitellään alku0

koodi näytetään alla:

  1. class Solution
  2. {
  3. public:
  4. string multiply(string num1, string num2)
  5. {
  6. //先逆序两个字符串
  7. reverse(num1.begin(), num1.end());
  8. reverse(num2.begin(), num2.end());
  9. //定义一个数组tmp
  10. int m = num1.size(), n = num2.size();
  11. vector<int> tmp(m + n - 1);
  12. //无进位相乘然后相加
  13. for(int i = 0; i < m; i++)
  14. for(int j = 0; j < n; j++)
  15. tmp[i + j] += (num1[i] - '0') * (num2[j] - '0');
  16. //处理进位
  17. string ret;
  18. int t = 0, cur = 0;
  19. while(cur < m + n - 1 || t != 0)
  20. {
  21. if(cur < m + n - 1) t += tmp[cur++];
  22. ret += to_string(t % 10);
  23. t /= 10;
  24. }
  25. if(t) ret += to_string(t);
  26. //处理前置0
  27. while(ret.back() == '0' && ret.size() > 1) ret.pop_back();
  28. reverse(ret.begin(), ret.end());
  29. return ret;
  30. }
  31. };

Tämä lopettaa merkkijonoon liittyvät kysymykset