leetcode - Self Crossing

9 篇文章 0 订阅

Self Crossing

问题来源

昨晚于CSDN问答中看到一条提问,leetcode-C++程序里面一个很奇怪的bug!,这个问题是由于隐式数据类型转换引起的,举个栗子:

         int i = -1;
unsigned int u = 100;
cout << "Does u is biger than i? " << (u>i? "True!":"False!") << endl;

你猜猜输出的内容是什么,也许聪明的你会蒙对答案就是:

does u is biger than i? False!

这是为什么呢?好吧,如果不清楚细节可以往下看,C++编译器的隐式转换机制在上面的比较运算中产生了负面的作用,因为unsigned 和 int 都是32-bit数值,而且前者表达的数值是远比后者的大的,因为int类型符号位占用了其中一个比特,2^32 > 2^31,因此编译器认为 int 应该转换成 unsigned 类型再进行比较。这就是根源,负数在内存的存储是以 2’补码的形式保存的,也就是说 -1 的32-bit的数据其实是 0xffffffff 当其转换成为 unsigned 后就变成了正数,而且值是 unsigned int 的最大值 2^32,这时再和 u 的区区 100 这个小数值相比,当然是大牛了!所以注意无符号数的使用场合非常重要,而这种隐式类型转换还相当的隐蔽,编译器不会给任何一点提示,如果使用 vector.size() 这样一些返回无符号数的方法更是如此。

在问答页中顺手点开了相关的 LeetCode 官方网站,发现一条有趣的题 Self Corssing,原题内容如下:

You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north, then x1 metres to the west, x2 metres to the south,x[3] metres to the east and so on. In other words, after each move your direction changes counter-clockwise.

Write a one-pass algorithm with O(1) extra space to determine, if your path crosses itself, or not.

Example 1:
Given x = [2, 1, 1, 2],

┌───┐
│      │
└───┼──>
        │

Return true (self crossing)
Example 2:
Given x = [1, 2, 3, 4],

┌──────┐
│            │
│
│
└────────────>

Return false (not self crossing)
Example 3:
Given x = [1, 1, 1, 1],

┌───┐
│      │
└───┼>

Return true (self crossing)

问题大意就是,给定一个向量,其第一个数表示向北移动的米数,第二个数表示向西移动的米数,第三个数表示向南移动的米数,第四个数表示向东移动的米数,其余数字依些循环进行。实现一个 O(1) 复杂度的一次扫描算法,求解移动的路线是不是出现交叉。

代码实现

    #include <iostream>
    #include <vector>

    using namespace std;

    // Accepted
    bool isSelfCrossing(vector<int>& x) {
        int i, c = x.size();
        for(i=3;i<c;i++){
            int x0 = x.at(i);
            int x1 = x.at(i-1);
            int x2 = x.at(i-2);
            int x3 = x.at(i-3);
            int x4 = i>3? x.at(i-4):0;
            int x5 = i>4? x.at(i-5):0;
            if( !(x0-x2<0) && !(x1-x3>0) ) return true;
            if( i>3 && (x0+x4==x2 && x1+x5==x3) )  return true;
            if( i>4 && ( x1<=x3 && x0+x4>=x2 && x0>=x4 && x1+x5>=x3) ) return true;
        }
        return false;
    }

    void assert(int a[], int c, bool b, bool assert){
        int i;
        cout << (b!=assert? "Failure!":"OK!") << " {";
        for(i=0; i<c-1; i++) cout << a[i] << ",";
        cout << a[i] << "} " <<  (b? "Self crossing":"Pass") << endl;
    }

    void test(int d[], int c, bool key){
        //cout << "sizeof []:" << sizeof(d); // sizeof(int)
        vector<int> x(d, d+c);
        assert(d, c, isSelfCrossing(x), key);
    }

    int main(){
        int d[] = {1,1,2,1,1};
        int c = sizeof(d)/sizeof(int);
        vector<int> x(d, d+c);
        assert(d, c, isSelfCrossing(x), true);

        int d0[] = {1,1,2,2,1,1};
        test(d0, 6, true);

        int da[] = {1,2,2,2};
        test(da, 4, false);

        int db[] = {1,1,2,2,3,3,4,4,10,4,4,3,3,2,2,1,1,};
        test(db, 8, false);
        test(db, 11, false);
        test(db, 12, false);
        test(db, 13, false);
        test(db, 17, false);

        int dc[] = {1,1,2,2,3,1,1};
        test(dc, 7, true);

        int dd[] = {2,2,3,1,1};
        test(dd, 4, false);

        int de[] = {1,1,3,2,1,1};
        test(de, 6, false);

        int d1[] = {1, 1, 1, 1};
        test(d1, 4, true);

        int d2[] = {1, 2, 3, 4};
        test(d2, 4, false);

        int d3[] = {2, 1, 1, 2};
        test(d3, 4, true);

        int d4[] = {9,8,6,4,2};
        test(d4, 5, false);

        int d5[] = {2,1,4,4,3,3,2,1,1};
        test(d5, 5, false);
        test(d5, 9, true);

        return 0;
    }

测试输出:

    C:\c\src\base_struct>g++ -o vector vector.cpp && vector.exe
    OK! {1,1,2,1,1} Self crossing
    OK! {1,1,2,2,1,1} Self crossing
    OK! {1,2,2,2} Pass
    OK! {1,1,2,2,3,3,4,4} Pass
    OK! {1,1,2,2,3,3,4,4,10,4,4} Pass
    OK! {1,1,2,2,3,3,4,4,10,4,4,3} Pass
    OK! {1,1,2,2,3,3,4,4,10,4,4,3,3} Pass
    OK! {1,1,2,2,3,3,4,4,10,4,4,3,3,2,2,1,1} Pass
    OK! {1,1,2,2,3,1,1} Self crossing
    OK! {2,2,3,1} Pass
    OK! {1,1,3,2,1,1} Pass
    OK! {1,1,1,1} Self crossing
    OK! {1,2,3,4} Pass
    OK! {2,1,1,2} Self crossing
    OK! {9,8,6,4,2} Pass
    OK! {2,1,4,4,3} Pass
    OK! {2,1,4,4,3,3,2,1,1} Self crossing

这题目官方统计数据 Total Accepted: 2337 Total Submissions: 13733 Difficulty: Medium,提交正确率大概是1:6,我提交了不少于6次,算是拉低总体水平的那部分。提交时会给出出错时的输入数据,我就用这些数据来作分析的,太懒了不想去准备数据。尽管这是一道中级难度题目,但是昨晚搞到半夜三更都没弄出来,主要还是思路方向上的问题,容易往混乱的方向走,这一走不容易出来答案。草图就是根据官方数据画的,在里面绕了好久:

pencil draw

看看原始的代码就知道有多混乱了:

    //raw version 2016/3/8 14:01
    bool isSelfCrossing(vector<int>& x) {
        int i, c = x.size();
        for(i=3;i<c;i++){
            int x1st = x.at(i-1);
            int x2nd = x.at(i-2);
            int x3rd = x.at(i-3);
            int x4th = i>3? x.at(i-4):0;
            int x5th = i>4? x.at(i-5):0;
            int o = x.at(i)-x2nd;
            int g = x1st-x3rd;
            bool fi = ( !(g>0) && !(o<0) );
            bool fe = i>3 && ( x.at(i)>=x4th && g+x5th<=0 );
            bool fs = i>3 && !(g>0) && x.at(i)>=x4th && (o+x4th>=0 && g+x5th>=0);
            if( fi || fe || fs ) return true;
        }
        return false;
    }

参考资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值