//給定長度爲m的短字符串s1,以及一個長度爲n的長字符串str,m<n
//問能否在str中找到一個長度爲m的連續子串使得這個子串剛好由s1的m個字符組成,順序無所謂,返回任意滿足條件的一個子串的起始位置
第一種思路,比較常規的,時間複雜度是O(n*m), 先給子串中的每個字符構建一個hash表, 然後給str中長度爲m的子串也構建一個hash表, 比較2個hash是否相同,如果相同,那就是同源異構子串.
- (void)test1 {
//給定長度爲m的字符串s1,以及一個長度爲n的字符串str
//問能否在str中找到一個長度爲m的連續子串使得這個子串剛好由s1的m個字符組成,順序無所謂,返回任意滿足條件的一個子串的起始位置,未找到返回-1
NSString * str = @"acdabcaafg";
NSString * s1 = @"abac";
NSDictionary<NSString*,NSNumber*> * s1Dic = [self getDictionaryWithStr:s1];
for (int i=0; i<str.length-s1.length; i++) {
NSString * temp = [str substringWithRange:NSMakeRange(i, s1.length)];
NSDictionary * tempDic = [self getDictionaryWithStr:temp];
if ([tempDic isEqual:s1Dic]) {
NSLog(@"找到了 %d %@",i,temp);
}
}
}
// 把字符串中的每個字符串截取成一個數組
- (NSArray <NSString *> *)subStr:(NSString *)str {
NSMutableArray * array = [NSMutableArray array];
for (int i = 0; i<str.length; i++) {
NSString * oneStr = [str substringWithRange:NSMakeRange(i, 1)];
[array addObject:oneStr];
}
return array;
}
/// 構建每個字符組成的字典,統計每個字符出現的次數
- (NSMutableDictionary *)getDictionaryWithStr:(NSString *)str {
NSArray <NSString *> * array = [self subStr:str];
NSMutableDictionary * dic = [NSMutableDictionary dictionary];
for (NSString * key in array) {
if (dic[key]) {
dic[key] = @([dic[key] intValue] + 1);
continue;
}
dic[key] = @(1);
}
return dic;
}
網上的比較優秀的一個, 對這個比較是否相同做了優化, 首先還是子串構造出一個hash表,但是不是通過2個hash表是否相同,而是用了一個wrongNum,記錄不符合的字符數量,如果不符合的字符數量超過0,那就不滿足條件,如果爲0,那就是同源異構子串.
用子串構造出的hash表, 然後str生成一個大小爲m的窗口, str中的窗口來填這個hash表,如果填到所有值爲0,那就是同源異構子串.
比上一個算法, 好處就是時間複雜度爲O(n), 但是有了這個wrongNum,維護起來,理解起來有點難了.
- (void)test2{
//給定長度爲m的字符串s1,以及一個長度爲n的字符串str
//問能否在str中找到一個長度爲m的連續子串使得這個子串剛好由s1的m個字符組成,順序無所謂,返回任意滿足條件的一個子串的起始位置,未找到返回-1
NSString * str = @"acdabcaafg";
NSString * s1 = @"acd";
NSMutableDictionary<NSString*,NSNumber*> * s1Dic = [self getDictionaryWithStr:s1];
int wrongNum = 0; // 記錄s1Dic中的錯誤數量
int right = 0; // 窗口右側值
NSArray * strArray = [self subStr:str];
// 構造第一個窗口
for (; right<s1.length; right++) {
// 依次把字母加進去,如果這個字母沒有在s1Dic中出現,說明是多添加的,比如f,那麼需要把字典中的錯誤數量加1
if ([s1Dic[ strArray[right] ] intValue] <= 0){
wrongNum ++;
}
s1Dic[ strArray[right] ] = @([s1Dic[ strArray[right] ] intValue]-1);
}
for (; right<str.length; right++) {
if (wrongNum == 0) {
NSLog(@"找到了 就是 %lu",right-s1.length);
}
// 把下一個字母加到窗口中去,如果爲0,需更新錯誤數量
if ([s1Dic[ strArray[right] ] intValue] <= 0){
wrongNum ++;
}
s1Dic[ strArray[right] ] = @([s1Dic[ strArray[right] ] intValue]-1);
// 把窗口最左邊的字母去掉,如果爲0,減少錯誤數量
if ([s1Dic[ strArray[right-s1.length] ] intValue] < 0){
wrongNum --;
}
s1Dic[ strArray[right-s1.length] ]= @([s1Dic[ strArray[right-s1.length] ] intValue]+1);
}
// 最後一個結束的判斷
if (wrongNum == 0) {
NSLog(@"找到了 就是 %lu",right-s1.length);
}
NSLog(@"尋找結束");
}
// 把字符串中的每個字符串截取成一個數組
- (NSArray <NSString *> *)subStr:(NSString *)str {
NSMutableArray * array = [NSMutableArray array];
for (int i = 0; i<str.length; i++) {
NSString * oneStr = [str substringWithRange:NSMakeRange(i, 1)];
[array addObject:oneStr];
}
return array;
}
/// 構建每個字符組成的字典,統計每個字符出現的次數
- (NSMutableDictionary *)getDictionaryWithStr:(NSString *)str {
NSArray <NSString *> * array = [self subStr:str];
NSMutableDictionary * dic = [NSMutableDictionary dictionary];
for (NSString * key in array) {
if (dic[key]) {
dic[key] = @([dic[key] intValue] + 1);
continue;
}
dic[key] = @(1);
}
return dic;
}
如果2個字符串的字符一樣,無論順序是否一致,都可以認爲是兄弟字符串,比如"abcc" , "acbc" 就是兄弟字符串 , 寫出一個算法,判斷是否是兄弟字符串.
生成一個hash表統計每個字符出現的次數,然後比較hash表的內容是否一致,如果一致,就說明是兄弟字符串.
//測試用例
// int result = isBrother("abcc", "ac");
int result = isBrother("wwwbaiducom", "combaiduwww");
// int result = isBrother("abcc", "acbcsda");
// int result = isBrother("abcc", "ccbb");
// int result = isBrother("abcc", "acbd");
// int result = isBrother("abcc", "acbc");
NSLog(@"%d",result);
int isBrother(char * str1,char * str2) {
// 2個桶保存每次字符出現的次數
int arrayA[26] ={0};
int arrayB[26] ={0};
// 生成第一個桶, 字符-'a'就是桶的下標
for (int i = 0; str1[i]!='\0'; i++) {
arrayA[str1[i]-'a'] ++;
}
for (int i = 0; str2[i]!='\0'; i++) {
arrayB[str2[i]-'a'] ++;
}
// 比較桶內元素的數量
for (int i = 0; i<26; i++) {
if (arrayA[i] == arrayB[i]) {
continue;
}
return 0;
}
return 1;
}