leetcode problem 17 için iki çözüm oluşturdum; bir telefon numarası kombinasyonundan olası tüm metin dizelerini oluşturmanızı ister. "3"
, ["d","e","f"]
sonuçlarıyla sonuçlanır.İki algoritmanın Big-O analizi
Benim ilk çözüm dizeleri oluşturmak için bir özyinelemeli bir algoritma kullanır ve aşağıda verilmiştir:
class Solution {
public:
void fill_LUT(vector<string>& lut) {
lut.clear();
lut.push_back(" ");
lut.push_back("");
lut.push_back("abc");
lut.push_back("def");
lut.push_back("ghi");
lut.push_back("jkl");
lut.push_back("mno");
lut.push_back("pqrs");
lut.push_back("tuv");
lut.push_back("wxyz");
}
void generate_strings(int index, string& digits, vector<string>& lut, vector<string>& r, string& work) {
if(index >= digits.size()) {
r.push_back(work);
return;
}
char idx = digits[index] - '0';
for(char c : lut[idx]) {
work.push_back(c);
generate_strings(index+1, digits, lut, r, work);
work.pop_back();
}
}
vector<string> letterCombinations(string digits) {
vector<string> r;
vector<string> lut;
fill_LUT(lut);
if(digits.size() <= 0)
return r;
string work;
generate_strings(0, digits, lut, r, work);
return r;
}
};
Ben büyük-O ile biraz paslı değilim, ama uzay karmaşıklığı için O(n)
olacağını bana görünen Yinelemeli çağrı, yani maksimum derinliği, tampon dizisi için O(n)
ve sonuçtaki dizeler için O(n*c^n)
. Bu O(n+n*c^n)
olarak toplanır mı?
Zaman karmaşıklığı için biraz kafam karıştı. Yinelemenin her seviyesi c
ibaresi + pops + tekrar aramaları bir sonraki seviyeye kadar işlem sayısı ile çarparak gerçekleştirir, böylece c^1 + c^2 + ... + c^n
gibi görünür. Ayrıca, c^n
n
uzunluk dizgilerinin kopyaları vardır. Bunu güzel bir büyük-O sunumuna nasıl katlarım?
ikinci çözüm karışık sayı tabanı numarası olarak sonuç sayısını görür ve onaltılık dize dönüştürme için bir int performans gösterebileceği gibi bir dizeye dönüştürür:
class Solution {
public:
void fill_LUT(vector<string>& lut) {
lut.clear();
lut.push_back(" ");
lut.push_back("");
lut.push_back("abc");
lut.push_back("def");
lut.push_back("ghi");
lut.push_back("jkl");
lut.push_back("mno");
lut.push_back("pqrs");
lut.push_back("tuv");
lut.push_back("wxyz");
}
vector<string> letterCombinations(string digits) {
vector<string> r;
vector<string> lut;
fill_LUT(lut);
if(digits.size() <= 0)
return r;
unsigned total = 1;
for(int i = 0; i < digits.size(); i++) {
digits[i] = digits[i]-'0';
auto m = lut[digits[i]].size();
if(m > 0) total *= m;
}
for(int i = 0; i < total; i++) {
int current = i;
r.push_back(string());
string& s = r.back();
for(char c : digits) {
int radix = lut[c].size();
if(radix != 0) {
s.push_back(lut[c][current % radix]);
current = current/radix;
}
}
}
return r;
}
};
Bu durumda ben uzay karmaşasının, ilk çözümün tampon ve özyinelemesine benzer şekilde O(n*c^n)
olduğuna ve zaman karmaşıklığının, ilk döngü için O(n)
ve olası sonuçların her biri için bir sonuç dizesi oluşturmak üzere ek bir O(n*c^n)
olması gerektiğine inanıyoruz. Bunun için son büyük-O O(n+n*c^n)
. Düşünce sürecim doğru mu?
Düzenleme:, koda bazı konulara açıklık eklemek "234"
bir giriş dizesi hayal etmek. İlk özyinelemeli çözüm (0, "234", lut, r, work)
argümanlarıyla generate_strings
'u arayacaktır. lut
, bir sayıyı karşılık gelen karakterlere dönüştüren bir görünüm tablosudur. r
, sonuçtaki dizeleri içeren vektördür. work
, çalışmanın gerçekleştirildiği bir arabellektir.
ilk özyinelemeli çağrı ardından endeks 0
haneli "abc"
ile karşılık 2
olduğunu, work
için a
itmek olduğunu gördükten sonra argümanları (1, "234", lut, r, work)
ile generate_strings
arayacak. Çağrı geri döndüğünde, b
'u work
'a gönderir ve durulayıp tekrar eder.
index
, digits
boyutuna eşit olduğunda, benzersiz bir dize oluşturuldu ve dize r
'a aktarıldı. İkinci çözüm için
, girdi dizisi birinci tamsayı temsil var için bu ASCII temsil var dönüştürülür. Örneğin
"234"
,
"\x02\x03\x04"
'a dönüştürülür.Ardından kod, arama tablosundaki karşılık gelen karakterlerin sayısını aramak için dizinler olarak kullanır ve sonuçta kullanılacak toplam dizge sayısını hesaplar. Örneğin. Giriş dizgisi
"234"
ise,
2
, 3 karakterden oluşan
abc
ile karşılık gelir.
3
, 3 karakterden oluşan
def
ile karşılık gelir.
4
, 3 karakterden oluşan
ghi
ile karşılık gelir. Toplam olası dizi sayısı
3*3*3 = 27
. Daha sonra kod, olası dizelerin her birini temsil etmek için bir sayaç kullanır.
i
,
15
ise, ilk rakamın (
a
) birinci karakteri ile karşılık gelen
0
olan
15 % 3
'u bulmak suretiyle değerlendirilir. Daha sonra
15
'u
3
ile
5
arasına bölün.
5 % 3
,
f
olan ikinci hane için üçüncü karaktere karşılık gelen
2
şeklindedir. Son olarak
3
tarafından
5
'u bölün ve
1
elde edersiniz.
1 % 3
,
h
üçüncü rakamı için ikinci karaktere karşılık gelen
1
'dur. Bu nedenle,
15
numaralı numaraya karşılık gelen dize
afh
'dur. Bu her sayı için gerçekleştirilir ve sonuç dizeleri
r
'da depolanır.
Algo fikirlerini İngilizce açıklar mısınız? Kodu okurken baş ağrısı bir sürü kaydetmek. – cuongptnk
O, c^n baskın olduğunda n. Basitçe O (c^n) diyebilir ve doğru olabilirsiniz. –
@cuongptnk emin, sorumun sonunda biraz daha ayrıntı ekledim. – Alden