الفنون رقم 003
الفنون رقم 003
ARTS هو نشاط بدأه
由左耳朵耗子--陈皓: قم بإجراء سؤال واحد على الأقل عن خوارزمية leetcode كل أسبوع، واقرأ مقالًا تقنيًا واحدًا على الأقل باللغة الإنجليزية وعلق عليه، وتعلم مهارة فنية واحدة على الأقل، وشارك المقالة مع الآراء والأفكار. (أي أن الخوارزمية والمراجعة والنصائح والمشاركة يشار إليها باسم ARTS) وتستمر لمدة عام واحد على الأقل.
فنون 003
هذه هي المقالة الثالثة، وهي مكتوبة بشكل سيء نسبيًا. وآمل أن تصبح أفضل وأفضل في المستقبل.
سؤال خوارزمية الخوارزمية
سؤال خوارزمية leetcode 151 عكس الكلمات في سلسلة (كلمات عكسية في سلسلة) يمكن أن يكون: معتدل
Given an input string, reverse the string word by word.
Example:
Input: "the sky is blue",
Output: "blue is sky the".
Note:
A word is defined as a sequence of non-space characters.
Input string may contain leading or trailing spaces. However, your reversed string should not contain leading or trailing spaces.
You need to reduce multiple spaces between two words to a single space in the reversed string.
Follow up: For C programmers, try to solve it in-place in O(1) space.
给定一个字符串,逐个翻转字符串中的每个单词。
示例:
输入: "the sky is blue",
输出: "blue is sky the".
说明:
无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
进阶: 请选用C语言的用户尝试使用 O(1) 时间复杂度的原地解法。
إذا لم تأخذ في الاعتبار مشكلة المساحة، فهذه الخوارزمية بسيطة نسبيًا. اقلب السلسلة بأكملها، ثم اقلب كل كلمة. تكمن صعوبة هذا السؤال في كيفية إزالة المسافات الزائدة، بما في ذلك المسافات في البداية، والمسافات في النهاية، والمسافات الزائدة بين الكلمات. التنفيذ على النحو التالي:
void ReverseString(char* str,int min,int max) {
int i = min;
int j = max;
while (i < j) {
char temp = * (str + i);
* (str + i) = * (str + j);
* (str + j) = temp;
i++;
j--;
}
}
//翻转字符串
void reverseWords(char *fdg) {
RemoveEmptyChar(fdg);
ReverseString(fdg,0,strlen(fdg) -1);
int i = 0;
int j = 0;
while (*(fdg + j)) {
if (*(fdg + j) == ' ') {
ReverseString(fdg,i,j-1);
i=j+1;
}
j++;
}
ReverseString(fdg,i,j-1);
}
//去掉空格
void RemoveEmptyChar(char* str) {
//先去掉尾部的空格
int j = strlen(str) -1;
while (*(str + j) == ' ') {
*(str + j) = '\0';
j--;
}
//去掉头部的空格
int i = 0;
while (*(str + i) == ' ') {
i++;
}
if(i > 0){
int count = 0;
while ((count < strlen(str) - i) && *(str +i + count)) {
*(str + count) = *(str +i + count);
count++;
}
*(str + count) = '\0';
}
//去掉中间的空格
int m = 0;
int flag = 0;
while (m < strlen(str)) {
if (*(str + m) == ' '){
flag++;
m++;
continue;
}
if (flag > 1) {
int count = 0;
while ((count < strlen(str) -m)) {
*(str + m - flag + 1 + count) = *(str + m + count);
count++;
}
*(str + m - flag + 1 + count) = '\0';
m = m - flag ;
}
flag = 0;
m++;
}
}
تواجه هذه الخوارزمية مشكلة في Leetcode، وهي أن المهلة ستنتهي. وكما ترى مما سبق، لا يوجد مجال للتحسين في طريقة تقليب الأوتار. يجب أن يكون سبب المهلة طريقة إزالة المسافات. يتمثل تنفيذ طريقة إزالة المسافات في أنه في حالة مواجهة مسافات إضافية، سيتم نقل السلسلة بعد المسافات للأمام. في أسوأ الحالات، يجب أن يكون عدد تحركات الأحرف تقريبًا: يتم نقل الحرف الثاني مرة واحدة، ويتم نقل الحرف الثالث مرتين، ويتم نقل الحرف n-1 مرات، ويكون التعقيد الزمني هو O(n<sup>2</sup>). في الواقع، ليست هناك حاجة للتحرك عدة مرات. يجب نقل حرف واحد مرة واحدة فقط. الطريقة المحسنة لإزالة المسافات هي كما يلي:
void RemoveEmptyChar1(char* str) {
char * i = str;
char * j = str;
while (*i && (*i == ' ')) {
if (i == str) {
j = i;
while (*j && (*j == ' ')) {
j++;
}
if (!*j) {//说明全是空格
i = j;
}
while (*j && (*j != ' ')) {
*i = *j;
*j = ' ';
i++;
j++;
}
}
else{
if (*(i+1) == ' ') {
j = i+ 1;
while (*j && (*j == ' ')) {
j++;
}
i++;
while (*j && (*j != ' ')) {
*i = *j;
*j = ' ';
i++;
j++;
}
}
else{
i++;
}
}
}
//先去掉尾部的空格
int m = strlen(str) -1;
while (*(str + m) == ' ') {
*(str + m) = '\0';
m--;
}
}
بعد التحسين، أصبح وقت تشغيل leetcode هو 4 مللي ثانية، وأفضل إجابة مقدمة على leetcode هي 0 مللي ثانية. لقد ألقيت نظرة ووجدت أن طريقة قلب الخيط هي نفسها التي أستخدمها. الفرق هو طريقة إزالة المسافات. طريقة إزالة المسافات في 0ms هي كما يلي:
void updateString(char *s) {
int i = 0;
int end = 0;
int index = 0;
bool flag = false;
while (s[i] == ' ') {
i++;
}
while (s[i] != '\0') {
if (s[i] == ' ') {
flag = true;
} else {
if (flag) {
index = end + 1;
end = index + 1;
flag = false;
} else {
index = end;
end++;
}
if (i > index) {
s[index] = s[i];
s[i] = ' ';
}
}
i++;
}
s[end] = '\0';
}
ويمكن ملاحظة أنه لا توجد حلقة متداخلة في تنفيذه، مما يعني أنه استخدم حلقة واحدة فقط لإنجازها. عندما نفذها، كان يتحرك على الأكثر بشخصية واحدة في كل مرة. بالنسبة لتطبيقي أعلاه، في الحلقة، إذا كانت هناك حاجة إلى نقلها، فسيتم نقل كلمة واحدة على الأقل، وكل ذلك باستخدام حلقات متداخلة.
مراجعة
المقالة التالية تأتي من: https://littlebitesofcocoa.com/251-face-aware-image-views-with-aspectfillfaceaware;. يتحدث عن استخدام Sidefillfaceaware لإدراك أنه عند تعيين صورة لـ imageView، إذا كانت الصورة تحتوي على وجه، فيمكن عرض الوجه تلقائيًا في المركز.
طرق عرض الصور Face Aware باستخدام AspectFillFaceAware (استخدم AspectFillFaceAware للسماح لـ imageView بالتعرف على الوجوه)
عند استخدام UIImageViews، قد تؤدي أوضاع المحتوى المضمنة في بعض الأحيان إلى تضييق أسلوبنا.
عند استخدام UIImageViews، أحيانًا ما يدمر وضع المحتوى المدمج أسلوبنا ولا يمكنه تلبية احتياجاتنا.
في كثير من الأحيان، نعرض صور الأشخاص. في هذه الحالات، سيكون من الرائع أن يتم توجيه عرض الصورة بطريقة ما لقص الصورة حول وجه الشخص بذكاء.
في كثير من الأحيان، نعرض صور الأشخاص. في هذه الحالات، سيكون من الرائع أن يتمكن عرض الصورة من قص الصورة حول وجه الشخص بطريقة ذكية.
سنتعرف اليوم على مكتبة من Beau Nouvelle تسمى AspectFillFaceAware. الأمر بسيط للغاية، دعونا نلقي نظرة.
سنلقي اليوم نظرة على مكتبة صفية من Beau Nouvelle تسمى AspectFillFaceAware. انها بسيطة جدا، دعونا نلقي نظرة.
AspectFillFaceAware هو في الأساس مجرد امتداد لـ UIImageView. فهو يوفر طريقتين لتكوين طريقة عرض الصورة لتكون “مدركة للوجه”.
AspectFillFaceAware هو في الأساس مجرد امتداد لـ UIImageView. يوفر طريقتين لتكوين عرض الصورة لـ “التعرف على الوجه”.
الأول في Interface Builder، يمكننا تمكين الميزة عن طريق النقر على الميزة في المفتش. (ألا ترى الخيار؟ قم بتشغيل مشروعك مرة واحدة، ثم يجب أن يظهر).
الطريقة الأولى هي في Interface Builder، حيث يمكننا تمكين الميزة من خلال التنقل بين الميزات في المفتش. (ألا ترى الخيار؟ قم بتشغيل مشروعك مرة واحدة وسيظهر).
<img src=“/img/15334638167496.jpg” width=“50%” height=“50%” /> وهنا كيف يبدو:

يمكننا أيضًا تمكين الوظيفة في التعليمات البرمجية عن طريق تعيين صورة عرض الصورة باستخدام هذه الوظيفة الجديدة:
يمكننا أيضًا استخدام هذه الميزة الجديدة من خلال الكود:
imageView.set(الصورة: الصورة الرمزية، focusOnFaces: صحيح) يمكننا أيضًا وضع نصف قطر زاوية سريع على طبقة عرض الصورة لتجربة وظيفة “التعرف على الوجه” في عرض دائري. (أي الصور الرمزية للمستخدم):
يمكننا أيضًا وضع نصف قطر زاوية سريع على طبقة عرض الصورة لتجربة ميزة “التعرف على الوجه” في العرض الدائري. (أي الصورة الرمزية للمستخدم):
دع نصف القطر = imageView.bounds.size.width / 2.0 imageView.layer.cornerRadius = radius
تحت الغطاء، تستخدم المكتبة CIDetector منخفض الدقة مع نوع CDetectorTypeFace للتعامل مع اكتشاف الوجه الفعلي. هل تريد الغوص بشكل أعمق هنا؟ لقد قمنا بتغطية أجهزة كشف CI في اللدغة رقم 87.
تحت الغطاء، تستخدم المكتبة CIDetector منخفض الدقة من النوع CIDetectorTypeFace للتعامل مع اكتشاف الوجه الفعلي. هل تريد التعمق أكثر؟ لقد قدمنا نهج CIDetectors في اللدغة رقم 87.
نصيحة
####1 كيفية تعيين نقاط التوقف لأساليب النظام عند استخدام Xcode لتصحيح الأخطاء؟ الجواب هو نقطة التوقف. على سبيل المثال، لطريقة setContentInset، نقطة التوقف، يمكنك استخدام الأمر التالي:
breakpoint set -S setContentInset:
لمزيد من التفاصيل، يرجى الرجوع إلى: https://www.jianshu.com/p/8e9fc9a8ab78?from=jiantop.com
####2 تحسين UITableView يمكن القول أن تحسين UITableView هو موضوع لن يخرج أبدًا عن الموضة في تطوير iOS. فيما يلي ملخص لأفكار التحسين. يمكنك جوجل الطرق المحددة بنفسك. الفكرة العامة هي كما يلي:
-
قم بتقليل مقدار حسابات وحدة المعالجة المركزية/وحدة معالجة الرسومات 1.1 آلية إعادة استخدام الخلايا 1.2 قم بالتخزين المؤقت لارتفاع الخلية وإطار عناصر التحكم في الخلية في النموذج 1.3 تقليل مستوى الضوابط داخل الخلية 1.4 حقق تأثير الزاوية المستديرة للصورة الرمزية من خلال تغطية صورة الزاوية المستديرة
-
تحميل الخلايا حسب الطلب 2.1 قم بتحميل الخلايا المرئية فقط في طريقة cellForRow: 2.2 مراقبة التمرير السريع لعرض الجدول وحفظ فهارس الصفوف الثلاثة قبل نطاق التمرير المستهدف وبعده
-
المعالجة غير المتزامنة للخلايا 3.1 التحميل غير المتزامن لصور الشبكة 3.2 رسم الصور المحلية بشكل غير متزامن 3.3 الرسم غير المتزامن لـ UIView 3.4 الرسم غير المتزامن لـ NSString 3.5 الرسم غير المتزامن لـ UILabel
شارك
أثناء مشاركة سؤال اليوم، رأيت هذا السؤال في مجموعة اليوم
<img src=“/img/20180809225650469.png” width=“50%” height=“50%” />
أي واحد سوف تختار؟ اختر د؟
من المعرفة السابقة، يجب أن أختار D، ولكن عندما رأيت شخصًا يقول لي اختر B، قمت بتجربته. رمز الاختبار هو كما يلي:
- (void)viewDidLoad {
[super viewDidLoad];
for (int i =0; i < MAXFLOAT; i++) {
@autoreleasepool{
UIImage *img = [[UIView alloc] init];// A
UILabel *lab = [[UILabel alloc] init];// B
NSString *str = @"abc";
str = [str stringByAppendingString:@"xyz"];// C
}
}
}
والنتيجة هي أن B. B سوف يتسبب في استمرار زيادة الذاكرة. بعد الاختبار، وجد أنه بغض النظر عن مجموعة الإصدار التلقائي، فإن B سيؤدي إلى استمرار زيادة الذاكرة. الاثنان الآخران لن يتسببا في زيادة الذاكرة. إنه أمر غريب. من المنطقي أنه بعد إضافة @autoreleasepool، سيتم تحرير الذاكرة تلقائيًا عندما تصل إلى قيمة معينة. الشرح في المجموعة هو :
- المتعلقة بالمواضيع
- قامت Apple بتحسين حلقة for. إذا لم يكن UIView وفئاته الفرعية، فستتم معالجته في سلسلة رسائل فرعية.
- سيتم إنشاء كائن UIView تلقائيًا على الموضوع الرئيسي
- إذا قمت بوضع UIImage في سلسلة الرسائل الرئيسية للمعالجة، فستستمر الذاكرة في الارتفاع.
- تختلف طريقة تحرير تجمع الإصدار التلقائي للخيط الرئيسي عن طريقة إصدار الخيط الفرعي.
لكني مازلت لا أفهم السبب: 1 lab هو متغير محلي، باستثناء أنه يجب تحرير القوس الأيمن للحلقة. 2 تمت إضافة @autoreleasepool، والذي يجب تحريره عندما تصل الذاكرة إلى ذروتها. ؟ ؟ ؟
What to read next
Want more posts about ARTS?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home