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 回调方法,就需要每来一个请求就开一条线程,并且保活线程。这样的保活的线程太多,开销太大了。所以只需要保活一条固定的线程,在这个线程里发起请求、接收回调。