查找是否包含同源異構子串,其他字符串面試題

    //給定長度爲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;
    
}

 

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