ARTS #007

ARTS #007

Posted by Dan on September 27, 2018

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

ARTS 007

这是第7篇,之前看算法很多都是一头雾水,现在慢慢的有感觉了,有思路了,希望以后越来越好。

Algorihm 算法题

leetcode算法第15题3Sum: 难度:中等

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

最先想到的方法如下,当然也是效率最低的,在我的设备上,测试3000个数据,用时15s,


int** threeSum(int* nums, int numsSize, int* returnSize) {
    int **a= NULL;  //用二级指针动态申请二维数组
    int count = 0;
    for (int i =0; i < numsSize-2; i++) {
        for (int j =i+1; j < numsSize-1; j++) {
            for (int k  =j+1; k<numsSize; k++) {
                int first = nums[i];
                int second = nums[j];
                int third = nums[k];
                if (first + second + third == 0) {
                    if (first < second ) {
                        int temp =first;
                        first = second;
                        second = temp;
                    }
                    
                    if (first < third ) {
                        int temp =first;
                        first = third;
                        third = temp;
                    }
                    
                    if (second<third) {
                        int temp =second;
                        second = third;
                        third = temp;
                    }
                    
                    
                    int b = 0;
                    if(a != NULL){
                        for (int loop = 0; loop < count; loop++) {
                            int *aa = a[loop];
                            
                            if (aa[0] == first && aa[1] == second) {
                                //已经存在
                                b = 1;
                                break;
                            }
                            
                        }
                    }
                    
                    if (b == 0) {
                        int* result = (int*)malloc(sizeof(int) * (3));
                        result[0] = first;
                        result[1] = second;
                        result[2] = third;
                        
                        if (count ==0) {
                            count++;
                            a=(int**)malloc(sizeof(result)*count);
                        }
                        else{
                             count++;
                             a=(int**)realloc(a,sizeof(int*)*count);
                        }
                        
                        a[count-1] = result;
                    }
                }
            }
        }
    }
    *returnSize = count;
    return a;
}

看提示里面都是先排序,排序好之后我就想到了二分查找,于是实现如下

/插入排序
int* insertionSort(int nums[],int numsSize) {
    for (int j = 1; j < numsSize; j++) {
        int  sortingNum = nums[j];
        for (int i = j-1; i >=0; i--) {
            if (sortingNum < nums[i] ) {
                int temp = nums[i+1];
                nums[i+1] = nums[i];
                nums[i] = temp;
            }
        }
    }
    return nums;
}


// 二分查找
int binary_search(int arr[],int left,int right,int element){
    while(left<=right) {
        int mid = (left+right)/2;
        if(arr[mid]>element){
            right = mid - 1;
        }
        else if(arr[mid]<element){
            left = mid + 1;
        }
        else{
            return mid;
        }
    }
    return -1;
}

int** threeSum3(int* nums1, int numsSize, int* returnSize) {
    int *dddsd = insertionSort(nums1,numsSize);
    if(dddsd[0] > 0)
        return NULL;
    if(dddsd[numsSize-1] < 0)
        return NULL;
    int **result= NULL;  //用二级指针动态申请二维数组
    int count = 0;
    for (int i =0; i < numsSize-2 && dddsd[i] <=0; i++) {
        for (int j =numsSize-1; j >i && dddsd[j] >= 0; j--) {
            int first = dddsd[i];
            int second = dddsd[j];
            int third = 0 - first - second;
            int dfsd =binary_search(dddsd, i+1, j-1, third);
            if (dfsd == -1) {
                continue;
            }
            third = dddsd[dfsd];
        
            int b = 0;
            if(result != NULL){
                for (int loop = 0; loop < count; loop++) {
                    int *aa = result[loop];
                    
                    if (aa[0] == first && aa[1] == second) {
                        //已经存在
                        b = 1;
                        break;
                    }
                    
                }
            }
        
            if (b == 0) {
                int* sums = (int*)malloc(sizeof(int) * (3));
                sums[0] = first;
                sums[1] = second;
                sums[2] = third;
                
                if (count ==0) {
                    count++;
                    result=(int**)malloc(sizeof(sums)*count);
                }
                else{
                    count++;
                    result=(int**)realloc(result,sizeof(int*)*count);
                }
                
                result[count-1] = sums;
            }
        }
    }
    *returnSize = count;
    return result;
}

上面的算法,为了防止重复,在每次加入result的时候都会和之前的比较,这个操作其实可以优化掉,最终实现如下:

//插入排序
int* insertionSort(int nums[],int numsSize) {
    for (int j = 1; j < numsSize; j++) {
        int  sortingNum = nums[j];
        for (int i = j-1; i >=0; i--) {
            if (sortingNum < nums[i] ) {
                int temp = nums[i+1];
                nums[i+1] = nums[i];
                nums[i] = temp;
            }
        }
    }
    return nums;
}


// 二分查找
int binary_search(int arr[],int left,int right,int element){
    while(left<=right) {
        int mid = (left+right)/2;
        if(arr[mid]>element){
            right = mid - 1;
        }
        else if(arr[mid]<element){
            left = mid + 1;
        }
        else{
            return mid;
        }
    }
    return -1;
}

int** threeSum(int* nums, int numsSize, int* returnSize) {
    int *sortedNums = insertionSort(nums,numsSize);
    if(sortedNums[0] > 0)
        return NULL;
    if(sortedNums[numsSize-1] < 0)
        return NULL;
    
    int **result= NULL;  //用二级指针动态申请二维数组
    int count = 0;
    for (int i =0; i < numsSize-2 && sortedNums[i] <=0; i++) {
        if (i > 0 && sortedNums[i] == sortedNums[i-1]) {
            continue;
        }
        for (int j =numsSize-1; j >i && sortedNums[j] >= 0; j--) {
            if (j < numsSize-1 && sortedNums[j] == sortedNums[j+1]) {
                continue;
            }
            
            int first = sortedNums[i];
            int second = sortedNums[j];
            int third = 0 - first - second;
            int dfsd =binary_search(sortedNums, i+1, j-1, third);
            if (dfsd == -1) {
                continue;
            }
            third = sortedNums[dfsd];
        

            int* sums = (int*)malloc(sizeof(int) * (3));
            sums[0] = first;
            sums[1] = second;
            sums[2] = third;
        
            if (count ==0) {
                count++;
                result=(int**)malloc(sizeof(sums)*count);
            }
            else{
                count++;
                result=(int**)realloc(result,sizeof(int*)*count);
            }
            result[count-1] = sums;
        }
    }
    *returnSize = count;
    return result;
}

Review

Get with the program WANT a job with a successful multinational? You will face lots of competition. Two years ago Goldman Sachs received a quarter of a million applications from students and graduates. Those are not just daunting odds for jobhunters; they are a practical problem for companies. If a team of five Goldman human-resources staff, working 12 hours every day, including weekends, spent five minutes on each application, they would take nearly a year to complete the task of sifting through the pile.

想在一家成功的跨国公司谋个职位?那你要面对很多竞争。两年前高盛从在读学生和毕业生那儿收到了25万份求职申请。这不仅使得求职者成功机会渺茫,也给公司带来了现实的麻烦。假设高盛人力资源部的五名员工组成一个团队,全周无休地每天工作12个小时,在每份申请上花5分钟,也得花近一年才能筛选完这堆积如山的申请。

Little wonder that most large firms use a computer program, or algorithm, when it comes to screening candidates seeking junior jobs. And that means applicants would benefit from knowing exactly what the algorithms are looking for.

难怪大部分大公司在筛选低阶职位的求职者时都会用到一种计算机程序,也就是算法。这意味着求职者要是能确切知道算法在找什么,就能从中受益。

Victoria McLean is a former banking headhunter and recruitment manager who set up a business called City CV, which helps job candidates with applications. She says the applicant-tracking systems (ATS) reject up to 75% of CVs, or résumés, before a human sees them. Such systems are hunting for keywords that meet the employer’s criteria. One tip is to study the language used in the job advertisement; if the initials PM are used for project management, then make sure PM appears in your CV.

维多利亚.麦克莱恩(Victoria McLean)曾是一名银行业猎头和招聘经理,她创办了一家名叫City CV的公司,帮助求职者制作申请。她说,在由人处理简历前,应聘者追踪系统(ATS)会拒掉其中多达75%的申请。这些系统会搜寻符合雇主标准的关键字。一个小建议是研究招聘广告中使用的语言,如果文中是用首字母PM指代项目管理,那么就确保你的简历中有PM的字眼。

This means that a generic CV may fall at the first hurdle. Ms McLean had a client who had been a senior member of the armed forces. His experience pointed to potential jobs in training and education, procurement or defence sales. The best strategy was to create three different CVs using different sets of keywords. And jobhunters also need to make sure that their LinkedIn profile and their CV reinforce each other; the vast majority of recruiters will use the website to check the qualifications of candidates, she says.

这意味着一份没有针对性的简历可能连第一关都过不去。麦克莱恩有个客户曾是高级军官。从他的履历来看,他在培训和教育、采购或军备销售方面可能有工作机会。她说,最佳策略是用三套不同的关键词,做三份不同的简历。求职者还要保证他们在领英上的个人资料能和自己的简历呼应——绝大多数招聘人员会用这个网站来查证求职者的资质。

Passing the ATS stage may not be the jobhunter’s only technological barrier. Many companies, including Vodafone and Intel, use a video-interview service called HireVue. Candidates are quizzed while an artificial-intelligence (AI) program analyses their facial expressions (maintaining eye contact with the camera is advisable) and language patterns (sounding confident is the trick). People who wave their arms about or slouch in their seat are likely to fail. Only if they pass that test will the applicants meet some humans.

ATS可能还不是求职者面临的唯一技术关卡。包括沃达丰和英特尔在内的许多公司都采用了名为HireVue的视频面试服务。应聘者在回答视频提问时,AI程序会分析其面部表情(建议与摄像机保持眼神交流)和语言模式(听上去自信是要诀)。手臂乱挥或坐姿慵懒的人很可能会失败。只有通过了这个测试,求职者才会和一些面试人员面谈。

You might expect AI programs to be able to avoid some of the biases of conventional recruitment methods—particularly the tendency for interviewers to favour candidates who resemble the interviewer. Yet discrimination can show up in unexpected ways. Anja Lambrecht and Catherine Tucker, two economists, placed adverts promoting jobs in science, technology, engineering and maths on Facebook. They found that the ads were less likely to be shown to women than to men.

也许你以为AI程序能够避免传统招聘方法中存在的某些偏见,尤其是面试官倾向于选择与自己相似的求职者这一点。然而歧视会以意想不到的方式出现。安雅·兰布雷希特(Anja Lambrecht)和凯瑟琳·塔克(Catherine Tucker)这两位经济学家在Facebook上发布了宣传科学、技术、工程和数学领域工作机会的广告。她们发现这些广告被推送给男性的可能性比女性大。

This was not due to a conscious bias on the part of the Facebook algorithm. Rather, young women are a more valuable demographic group on Facebook (because they control a high share of household spending) and thus ads targeting them are more expensive. The algorithms naturally targeted pages where the return on investment is highest: for men, not women.

这并不是Facebook算法有意识的偏见造成的。相反,年轻女性在Facebook上是一个更有价值的群体(因为她们控制着很大一部分家庭支出),因此针对她们的广告价格更高。这些算法自然而然就瞄准了投资回报最高的页面:男性,而非女性。

In their book* on artificial intelligence, Ajay Agrawal, Joshua Gans and Avi Goldfarb of Toronto’s Rotman School of Management say that companies cannot simply dismiss such results as an unfortunate side-effect of the “black box” nature of algorithms. If they discover that the output of an AI system is discriminatory, they need to work out why, and then adjust the algorithm until the effect disappears.

多伦多大学罗特曼管理学院(Rotman School of Management)的阿杰伊·阿格拉沃尔(Ajay Agrawal)、约书亚·甘斯(Joshua Gans)和阿维·戈德法布(Avi Goldfarb)在他们关于人工智能的合著*中写道,公司不能把这类结果视作算法的“黑盒子”特性带来的令人遗憾的副作用,就简单打发了。如果它们发现一个AI系统的输出带有歧视性,就要找出原因,然后调整算法直到影响消失。

Worries about potential bias in AI systems have emerged in a wide range of areas, from criminal justice to insurance. In recruitment, too, companies will face a legal and reputational risk if their hiring methods turn out to be unfair. But they also need to consider whether the programs do more than just simplify the process. For instance, do successful candidates have long and productive careers? Staff churn, after all, is one of the biggest recruitment costs that firms face.

从刑事司法到保险,AI系统可能带来的偏见已在众多领域引发担忧。人事招聘也一样,如果公司的招聘手段有违公平,那它们将面临法律和声誉上的风险。但它们也要考虑,除了简化招聘流程,这些程序能否发挥更多作用。例如,成功受聘的求职者能否长期且富有成效地在公司工作?毕竟员工流失是公司面临的最大招聘成本之一。

There may also be an arms race as candidates learn how to adjust their CVs to pass the initial AI test, and algorithms adapt to screen out more candidates. This creates scope for another potential bias: candidates from better-off households (and from particular groups) may be quicker to update their CVs. In turn, this may require companies to adjust their algorithms again to avoid discrimination. The price of artificial intelligence seems likely to be eternal vigilance.

候选人渐渐学会调整简历以通过最初的AI测试,而算法也会相应改进,好筛掉更多的求职者,这可能会引发一场军备竞赛。这又为另一个潜在的偏见创造了空间:来自富裕家庭(以及特定群体)的求职者也许能更及时地更新简历。反过来,公司可能就需要再次调整算法,以避免歧视。运用人工智能的代价似乎是要永远保持警惕。

TIPS:

如何实现view的不同角不同圆弧大小

把view的四个直角都切成圆角:

    //设置圆角半径值    
    self.view.layer.cornerRadius  = 10.f;    
    //设置为遮罩,除非view有阴影,否则都要指定为YES的    
    self.view.layer.masksToBounds = YES;

2、把view某个直角切成圆角:

    //把 view2 的 左下角 和 右下角的直角切成圆角    
    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(120,10,80,80)];    
    view2.backgroundColor = [UIColor redColor];    
    [self.view addSubview:view2];        
    //设置切哪个直角
    //    UIRectCornerTopLeft     = 1 << 0,  左上角
    //    UIRectCornerTopRight    = 1 << 1,  右上
    //    UIRectCornerBottomLeft  = 1 << 2,  左下角
    //    UIRectCornerBottomRight = 1 << 3,  右下角
    //    UIRectCornerAllCorners  = ~0UL     全部角    
    //得到view的遮罩路径    
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view2.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(10,10)];    
    //创建 layer    
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];    
    maskLayer.frame = view2.bounds;    
//赋值    
maskLayer.path = maskPath.CGPath;

上面方法设置的圆角,每个圆角的弧度都是一样的,那么怎么实现四个角,不同的圆角大小呢?上面实现圆角的关键是CAShapeLayer的path,所以我们只有自定义这个path就可以了,实现如下:

- (void)setViewRadius:(UIView  *)view{
    CGFloat topLeftRadius = 50;
    CGFloat topRightRadius = 60;
    CGFloat bottomRightRadius = 40;
    CGFloat bottomLeftRadius = 30;
    
    CGFloat minx = CGRectGetMinX(view.bounds);
    CGFloat miny = CGRectGetMinY(view.bounds);
    CGFloat maxx = CGRectGetMaxX(view.bounds);
    CGFloat maxy = CGRectGetMaxY(view.bounds);
    
    UIBezierPath *path = [[UIBezierPath alloc] init];
    [path moveToPoint:CGPointMake(minx + topLeftRadius, miny)];
    
    [path addLineToPoint:CGPointMake(maxx - topRightRadius, miny)];
    [path addArcWithCenter:CGPointMake(maxx - topRightRadius, miny + topRightRadius) radius: topRightRadius startAngle: 3 * M_PI_2 endAngle: 0 clockwise: YES];
    
    [path addLineToPoint:CGPointMake(maxx, maxy - bottomRightRadius)];
    [path addArcWithCenter:CGPointMake(maxx - bottomRightRadius, maxy - bottomRightRadius) radius: bottomRightRadius startAngle: 0 endAngle: M_PI_2 clockwise: YES];
    
    [path addLineToPoint:CGPointMake(minx + bottomLeftRadius, maxy)];
    [path addArcWithCenter:CGPointMake(minx + bottomLeftRadius, maxy - bottomLeftRadius) radius: bottomLeftRadius startAngle: M_PI_2 endAngle:M_PI clockwise: YES];
    
    [path addLineToPoint:CGPointMake(minx, miny + topLeftRadius)];
    [path addArcWithCenter:CGPointMake(minx + topLeftRadius, miny + topLeftRadius) radius: topLeftRadius startAngle: M_PI endAngle:3 * M_PI_2 clockwise: YES];
    
    [path closePath];
    
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.path = path.CGPath;
    view.layer.mask = maskLayer;

再给出一个 UIView实现渐变色的demo

 UIColor *frameColor = [UIColor colorWithHexString:@"#FFB300"];
            UIColor *toColor = [UIColor colorWithHexString:@"#FF6100"];
            CAGradientLayer *gradientLayer = [CAGradientLayer layer];
            gradientLayer.locations = @[@0.0, @1.0];
            gradientLayer.startPoint = CGPointMake(0, 0);
            gradientLayer.endPoint = CGPointMake(1.0, 0);
            gradientLayer.frame = _bgImageView.bounds;
            gradientLayer.colors = @[(__bridge id)frameColor.CGColor, (__bridge id)toColor.CGColor];
            [_bgImageView.layer insertSublayer:gradientLayer atIndex:0];

Share:

今天有个知乎问答火了,当下(2018 年)腾讯的技术建设是否处于落后同体量公司的状态?,y一个叫toughguy的回答火了,不过作者的回答发布了一天就删除了,但是网上有备份,感兴趣的可以搜索一下

对于这个问题分享一下我的看法:

文章讲的是技术不行,人才储备不足,技术落户,公司内部规则制度比较死板。 我现在所在的公司其实也是这样,公司很多的制度不利于公司技术的发展,公司很多的小领导都是在公司待了5年以上的老人,水平一般,都是熬上去的,有的竟然不知道Git,现在还在用SVN,代码没人敢重构,因为没有测试用例,改出bug要承担责任,领导的态度就说能用就行。

一个团队的技术水平可以说取决于这个团队的领导,领导的格局够大,能力够强,整个团队的创造性就会很强,

如果一个领导,故步自封,追求稳定,自己不进步还阻挠别人用新技术,那完蛋,赶快走人。

在大公司,一个基层程序员很难改变这种情况的,要想改变这种情况我觉得只有从领导下手,

还有加班问题,其实大企业的很多加班都不是因为工作做不完,而是因为公司拿这个作为衡量工作量的标准。这样一搞,不管有事没事,加班时间要够。俗称面子工程。