查找是否包含同源异构子串,其他字符串面试题

    //给定长度为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;
    
}

 

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