ARTS #022

ARTS #022

Posted by Dan on January 18, 2019

ARTS是由左耳朵耗子--陈皓发起的一个活动: 每周至少做一个leetcode的算法题、阅读并点评至少一篇英文技术文章、学习至少一个技术技巧、分享一篇有观点和思考的文章。(也就是Algorithm、Review、Tip、Share简称ARTS),至少坚持一年。

ARTS 022

这是第22篇

Algorihm 算法题

648. Replace Words

Difficulty Medium

In English, we have a concept called root, which can be followed by some other words to form another longer word - let’s call this word successor. For example, the root an, followed by other, which can form another word another.

Now, given a dictionary consisting of many roots and a sentence. You need to replace all the successor in the sentence with the root forming it. If a successor has many roots can form it, replace it with the root with the shortest length.

You need to output the sentence after the replacement.

Example 1:

Note:

Input: dict = ["cat", "bat", "rat"]
sentence = "the cattle was rattled by the battery"
Output: "the cat was rat by the bat"

Solution

Language: C


/**判断str1是否以str2开头
 * 如果是返回1
 * 不是返回0
 * 出错返回-1
 * */
int is_begin_with(const char * str1,char *str2){
    if(str1 == NULL || str2 == NULL)
        return -1;
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    if((len1 < len2) ||  (len1 == 0 || len2 == 0))
        return -1;
    char *p = str2;
    int i = 0;
    while(*p != '\0')
    {
        if(*p != str1[i])
            return 0;
        p++;
        i++;
    }
    return 1;
}

/*方法,调用C库函数,*/
char* join(char *s1, char *s2){
    char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
    if (result == NULL)
        return NULL;
    
    strcpy(result, s1);
    strcat(result, s2);
    
    return result;
}

char* replaceWords(char** dict, int dictSize, char* sentence) {
    int i = 0;
    //先处理dict,把dict中词根 处理为最短词根
    while (i < dictSize) {
        char* str2 = dict[i];
        if (str2 == NULL) {
            i++;
            continue;
        }
        
        int j = i+1;
        while (j < dictSize) {
            char* str1 = dict[j];
            if (str1 == NULL) {
                j++;
                continue;
            }
            
            if (strcmp(str1, str2) == 0) {
                dict[j] = NULL;
                j++;
                continue;
            }
            
            if (is_begin_with(str1,str2)==1) {
                dict[j] = NULL;
                j++;

            }
            j++;
        }
        i++;
    }
    

    //分割字符串进行替换
    char * re = "";
    char * pch = strtok(sentence, " ");
    while (pch != NULL){
        if (strlen(re) > 0){
             re = join(re," ");
        };
        
        
        int j=0;
        while (j < dictSize) {
            char* str1 = dict[j];
            if (str1 == NULL) {
                j++;
                continue;
            }

            if ((strcmp(pch, str1) != 0) && (is_begin_with(pch,str1)==1)) {
                pch = str1;
                break;
            }
            j++;
        }
        re = join(re,pch);
        pch = strtok(NULL, " ");
        
    }
    return re;
}

Review

https://dandan2009.github.io/2018/12/28/exposing-NSDictionary/

TIPS

本周开源了两个控件: 高度自定义循环滚动Banner:https://github.com/dandan2009/DDCircleScrollViewBanner 弹窗控件,支持文字、图片、图文、自定义视图弹窗:https://github.com/dandan2009/DDPopUpView

Share

今天问了一个面试者的一个问题: AF2.x为什么需要常驻线程?

也就是这段代码的作用是什么:

+ (void)networkRequestThreadEntryPoint:(id)__unused object {
     @autoreleasepool {
          [[NSThread currentThread] setName:@"AFNetworking"];

          NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
          [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
          [runLoop run];
     }
}

+ (NSThread *)networkRequestThread {
     static NSThread *_networkRequestThread = nil;
     static dispatch_once_t oncePredicate;
     dispatch_once(&oncePredicate, ^{
          _networkRequestThread =
          [[NSThread alloc] initWithTarget:self
               selector:@selector(networkRequestThreadEntryPoint:)
               object:nil];
          [_networkRequestThread start];
     });

     return _networkRequestThread;
}

结果好几个面试者答的都不对,而且网上的很多答案也不对,这里再总结一下:

AF2.x是用NSURLConnection发起网络请求的,NSURLConnection 是被设计成异步发送的,调用了start方法后, NSURLConnection 会新建一些线程用底层的 CFSocket 去发送和接收请求,在发送和接收的一些事件发生后通知原来线程的Runloop去回调事件。但是原来的线程可能会已经被释放。

为了保证原来的线程不被释放,以保证正常接收到 NSURLConnectionDelegate 回调方法,就需要每来一个请求就开一条线程,并且保活线程。这样的保活的线程太多,开销太大了。所以只需要保活一条固定的线程,在这个线程里发起请求、接收回调。