查找是否包含同源異構子串

    //給定長度爲m的字符串s1,以及一個長度爲n的字符串str
   //問能否在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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章