Berbagi teknologi

Algoritma: Terkait string

2024-07-12

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

Daftar isi

Topik 1: Awalan umum terpanjang

Pertanyaan 2: Substring palindrom terpanjang

Topik 3: Jumlah biner

Pertanyaan 4: Mengalikan string


Topik satu:awalan umum terpanjang

Tulis fungsi untuk menemukan awalan umum terpanjang dalam array string

Jika tidak ada awalan umum, kembalikan string kosong""

Contoh 1:

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

Contoh 2:

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

petunjuk:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i]Hanya terdiri dari huruf kecil bahasa Inggris

Solusi 1: Perbandingan berpasangan

Solusi pertama adalah strategi perbandingan berpasangan. Pertama bandingkan dua string pertama. Setelah perbandingan, bandingkan awalan umum dari dua string pertama dengan string ketiga untuk mendapatkan awalan umum dari tiga awalan string pertama, dan seterusnya

kode tampil seperti di bawah ini:

  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. };

Solusi 2: Perbandingan terpadu

Perbandingan terpadu berarti membandingkan posisi yang sama dari semua string sekaligus untuk menentukan apakah posisinya sama hingga muncul karakter yang berbeda.

Akan ada situasi di luar batas di sini. Jika ada situasi di luar batas, berarti string tertentu telah berakhir, dan kemudian perbandingan dapat dihentikan.

kode tampil seperti di bawah ini:

  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. };

Topik 2:substring palindrom terpanjang

Memberimu seutas talis,naikkansSubstring palindrom terpanjang di

Contoh 1:

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

Contoh 2:

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

Algoritme enumerasi brute force biasa menetapkan dua pointer, satu i dan satu j, memperbaiki i, dan memindahkan j mundur. Setiap kali j dipindahkan, perlu ditentukan apakah string antara i dan j merupakan substring palindrom. j dipindahkan. Dan menilai apakah ada substring palindrom antara i dan j, kompleksitas waktu di sini adalah O(N^2), dan karena ada lapisan i yang bersarang di luar, yang digunakan untuk melintasi seluruh string, maka seluruh waktu pencacahan kekerasan Kompleksitasnya sangat tinggi, mencapai O(N^3). Mari kita lihat algoritma perluasan pusat yang dioptimalkan:

Solusi: Algoritma perluasan pusat

Algoritma perluasan pusat adalah:

①Perbaiki titik pusat
②Mulai dari titik tengah dan perluas ke kedua sisi (panjang ganjil dan genap perlu dipertimbangkan)

Artinya, titik pusat i tetap setiap kali, dan setiap kali diperluas ke kiri dan kanan i untuk menentukan apakah itu merupakan string palindrom. Kompleksitas waktu dari algoritma yang melintasi i adalah O(N), dan arah bersarangnya ada di kiri dan kanan i. Dengan perluasan, kompleksitas waktunya juga O(N), jadi pada akhirnya adalah O(N^2), yang jauh lebih optimal daripada solusi kekerasan yang disebutkan di atas .

Yang perlu diperhatikan adalah poin kedua dari algoritma pemuaian pusat. Bilangan ganjil dan genap perlu diperhatikan, karena bilangan ganjil menggerakkan penunjuk kiri dan kanan dari posisi i ke kiri dan kanan, sedangkan bilangan genap memerlukan penunjuk ke kiri dan kanan dari posisi i ke kiri dan ke kanan, sedangkan bilangan genap memerlukan penunjuk ke kiri dan kanan dari posisi i ke kiri dan ke kanan. kiri berada pada posisi i dan kanan berada pada posisi i+1, lalu gerakkan ke kiri dan ke kanan

Perlu dicatat bahwa panjang dalam kode adalah kanan - kiri - 1, karena jika kiri dan kanan saat ini menunjuk ke elemen yang sama, Anda perlu mengubah kiri--, kanan++. Jika tidak sama, keluar dari loop , jadi string kiri dan kanan lebih banyak daripada string palindrom. Sudah berpindah satu posisi, jadi dihitung panjangnya dari kanan - kiri - 1. Lihat gambar di bawah untuk lebih jelasnya:

Seperti terlihat pada gambar di atas, titik kiri dan kanan menuju titik saat ini untuk keluar dari loop, sehingga panjang substring palindrom aa adalah:
kanan - kiri - 1 = 3 - 0 - 1 = 2


kode tampil seperti di bawah ini:

  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. };

Topik ketiga:Jumlah biner

Memberi Anda dua string bineraDanb, mengembalikan jumlahnya sebagai string biner.

Contoh 1:

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

Contoh 2:

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

Pertanyaan ini membahas tentang menghitung penjumlahan presisi tinggi, melakukan operasi simulasi, dan mensimulasikan proses perhitungan vertikal.

Anda perlu menyetel dua pointer, cur1 dan cur2, untuk menunjuk ke dua string masing-masing, lalu menyetel variabel t untuk mewakili carry.

kode tampil seperti di bawah ini:

  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. };

Topik empat:Perkalian string

Diberikan dua bilangan bulat non-negatif yang direpresentasikan sebagai stringnum1Dannum2,kembalinum1Dannum2Produk dari , produknya juga dinyatakan dalam bentuk string.

Melihat:Anda tidak dapat menggunakan perpustakaan BigInteger bawaan apa pun atau langsung mengonversi input menjadi bilangan bulat.

Contoh 1:

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

Contoh 2:

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

Solusi 1: Simulasikan operasi vertikal

Dalam matematika, ini adalah bentuk vertikal dari kolom perkalian. Ini adalah metode yang paling mudah untuk dipikirkan.

Sebagai berikut:

Dapat kita pahami sebagai berikut, setiap angka dari 456 berikut ini dikalikan dengan angka 123 di atas, lalu dijumlahkan, maka diperoleh tiga rincian:

①Perkalian tingkat tinggi harus diisi dengan 0, karena ada satu bit yang salah saat menambahkan 738 dan 615, yang dapat dipahami sebagai 738 + 6150
②Proses memimpin 0, situasi 123 × 0 dapat terjadi, dalam hal ini jawabannya adalah 000 dan perlu diproses.
③Perhatikan urutan hasil perhitungan, karena penghitungan dilakukan dalam urutan terbalik, dan perkalian dihitung dari angka terakhir.

Namun metode ini tidak mudah untuk menulis kode. Kita perlu menggunakan metode ini untuk mengoptimalkannya.

Solusi Kedua: Optimalkan Solusi Satu

Kalikan dan tambahkan tanpa carry, dan carry diproses pada langkah terakhir:

Artinya, berapapun dikalikan, tidak akan ada carry, dan carry akan dilakukan setelah penambahan terakhir.

Demikian pula, saat memulai penghitungan, balikkan urutannya terlebih dahulu. Karena perkaliannya bisa berupa dua digit, representasi string tidak dapat digunakan sebagai gantinya, array dapat digunakan untuk menyimpan

Karena urutannya dibalik, subskrip yang bersesuaian dengan 123 adalah 2,1,0, dan subskrip yang bersesuaian dengan 456 juga adalah 2,1,0

Ada aturan yang sangat berguna: angka-angka yang disubkripsikan oleh i dan j dikalikan, dan hasilnya ditempatkan pada posisi ke-i + j dalam array.

① Tentukan array tmp dengan panjang m + n - 1 (m dan n sesuai dengan panjang dua bilangan yang dikalikan)
Subskrip dari dua bilangan yang dikalikan masing-masing adalah i dan j, dan hasil perhitungannya ditempatkan pada posisi ke-i + j dalam array.
②Setelah penambahan terakhir, barang bawaan perlu diproses
③Memproses awalan 0

kode tampil seperti di bawah ini:

  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. };

Ini mengakhiri pertanyaan terkait string