任務
題目和解題方法來源:左神(左程雲):深入解析字節跳動算法面試題與數據結構
用C++實現算法(原講解爲Java)。並通過隨機新建字符串進行測試。
源代碼於GitHub
題目
給定長度爲m的字符串aim,以及一個長度爲n的字符串str
問能否在str中找到- -個長度爲m的連續子串, 使得這個子串剛好由aim的m個字符組成,順序無所謂, 返回任意滿足條件的一個子串的起始位置,未找到返回-1
思路
基本方法:遍歷
找到str中所有字串substr,比較substr與aim是否成分相同(字母的種類和數量一致)
- 統計第一個串 各字符統計
- 遍歷第二個串 – 至0 則false
窗口法
遍歷所有可能的字串長度通過窗口:欠與還
解題
遍歷
//比較與aim長度相同的的所有子串是否含有與它成分一致,若有,返回偏移量,否則返回-1
int findAim(string str, string aim)
{
//cout << str.length() - aim.length() << endl;
if (str.length() < aim.length())
return -1;
//數組,統計字符範圍內的字符出現個數
string substr;
bool findAim;
for (int i = 0; i < str.length() - aim.length(); i++)
{
int count[255] = {0};
for (int i = 0; i < aim.length(); i++)
{
count[aim[i]]++;
}
substr = str.substr(i, aim.length());
findAim = true;
for (int i = 0; i < aim.length(); i++)
{
if (--count[substr[i]] < 0)
findAim = false;
}
if (findAim == true)
return i;
}
return -1;
}
窗口法
//比較與aim長度相同的的所有子串是否含有與它成分一致,若有,返回偏移量,否則返回-1
//法2:最優解,通過“窗口”
int findAim2(string str, string aim)
{
//cout << str.length() - aim.length() << endl;
if (str.length() < aim.length())
return -1;
//初始爲aim的各字符值
int count[255] = { 0 };
int* pcnt = count + 97;
for (int i = 0; i < aim.length(); i++)
count[aim[i]]++;
//記錄窗口與aim的交易關係
//初始值是字符總長度
int owe = aim.length();
//初始化第一個窗口
for (int i = 0; i < aim.length(); i++)
{
//若新增的是還在需要中的,那麼相當於“火中送碳”,owe--
if (count[str[i]]-- > 0)
owe--;
//若新增的是之前冗餘不被需要的,那麼相當於“供非所求”,owe++
else
owe++;
}
if (owe == 0)
return 0;
//移動“窗口”,每次移動:拿去一個字符,新增一個字符,共可移動str.length() - aim.length()次
//移除的字符是第i個,新增的字符是第i+aim.length()個
for (int i = 0; i <= str.length() - aim.length(); i++)
{
//字符
int removed = str[i], added = str[i + aim.length()];
//判斷
//若被移除的是之前冗餘不被接受的,那麼相當於“及時止損”,owe--
if (count[removed]++ < 0)
owe--;
//若被移除的是還在需要中的,那麼相當於“屋漏偏逢連夜雨”,owe++
else
owe++;
//若新增的是還在需要中的,那麼相當於“火中送碳”,owe--
if (count[added]-- > 0)
owe--;
//若新增的是之前冗餘不被接受的,那麼與最初發生的事情一致,owe++
else
owe++;
//全部抵消,世界和平,移動了i次窗口,位於第i+1處
if (owe == 0)
return i + 1;
}
return -1;
}
測試
生成隨機字符串
string generateArr(int len, int left, int right)
{
if (left > right)
return "";
string str;// = "I lsfjo st";
str.resize(len+1);
for (int i = 0; i < len ; i++)
{
str[i] = left + rand() % (right - left);
//cout<<str[i] << endl;
}
return str;
}