Self Crossing
- MD DocumEnT:3/8/2016 4:28:26 PM by Jimbowhy
- CSDN:http://blog.csdn.net/WinsenJiansbomber/article/details/50829101
问题来源
昨晚于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次,算是拉低总体水平的那部分。提交时会给出出错时的输入数据,我就用这些数据来作分析的,太懒了不想去准备数据。尽管这是一道中级难度题目,但是昨晚搞到半夜三更都没弄出来,主要还是思路方向上的问题,容易往混乱的方向走,这一走不容易出来答案。草图就是根据官方数据画的,在里面绕了好久:
看看原始的代码就知道有多混乱了:
//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;
}