求第n个数的值

第一题是网易互联网2015年的c/c++后台开发的编程题,题目的title似乎叫股神,大意可以简化为以下:

 

股票买进的价格为1,以后的第一天价格不变,第二天涨一天,第三天跌一天,接着涨两天,跌一天,张三天,跌一天。。。为方便起见,设每天增量或减量均为1,求第n天股票的价格?

解题思路:本题可以用传统的程序员思维解题,即从第一天开始计数,并用一个变量用来控制涨的循环次数,逐步累加,直到n天。此算法的复杂度为O(N),并无出彩地方,此处提供一种数学方法,可以讲算法复杂度将为O(1)

将涨跌看做一个整体,算出第n次涨跌后的总天数sum(n)

sum(0) = 1;

sum(1) = 1+1+1;

sum(2) = 1+1+2+2;

sum(3) = 1+1+2+3+3;

……..

sum(n) = 1+1+2+3+..n+n = 1+(1+n)*n/2+n  这是sum的通项

对此可以列出不等式

《求第n个数的值》

n为正整数,对x取整,可以得到第n天之前涨跌的次数x;这时n-sum(x)必定处于涨潮之内(想想为什么?)此时,可以求得第n天的股价为

n-sum(x)+sum(x)-2*x = n-2*x;

代码如下:

#include <iostream>
#include <cmath>
using namespace std;

//this is the version without using sqrt function to find i
int find_index(const int &n){
	int i=1,sum=0;
	for(;i<=n;i++){
		sum += i;
		sum++;
		if(sum > n)
		    break;
	}
	return i-1;
}

int main()
{
	int n;
	while(cin >>n){
//		int k = find_index(n-1);
        int k = (-3+sqrt(1+8*n))/2;
		cout <<n-2*k <<endl;
	}
	return 0;
}

第二题是indeed公司的某道笔试题,题目大致意思如下:

对于平面座标系上的所有整数座标,规定每个座标点的大小如下:

点A(xA,yB)and  B(xB,yB)

若|xA|+|yA| >|xB|+|yB| 则点A大于点B,若绝对值之和相等,则比较x座标的绝对值,若仍然相等,则比较x的大小,具有较大x值得点较小(譬如点(1,5)小于(-1,5),因为前一个座标的x轴数值较大);再相等的话比较y的大小,具有较大y值的点较小;

将平面上所有点按从小到大排序,求出第n个点

此题的解题思路与上述题目一致,即先定义点的长度为座标点绝对值之和,先求出第n个点的长度,接着求出改点在该长度中的位置。譬如

长度为1的点有(1,0),(-1,0),(0,1),(0,-1)

长度为2的点有(2,0)(-2,0)(1,1)(1,-1)(-1,1)(-1,-1)(0,2)(0,-2)

。。。

对于长度为n的点,其个数a,不难写出其通项公式:

a(0) = 1;

a(1) = 4;

a(2) = 8;

a(i) = 4*i;   // i 大于等于1

其前n项和为sum(n)

《求第n个数的值》《求第n个数的值》《求第n个数的值》

先求出第n个点的长度

《求第n个数的值》《求第n个数的值》《求第n个数的值》

如果remain为0,则第n个点就是(0,-i),否则,第n个点的长度为1+i,再根据remain的大小找出在长度为i+1的点中找出其第remain个点,即是所求点

以下是参考代码,若有bug,欢迎各位同行校正指出

代码提供了两个版本,一个是利用累加的方法求得i,另一个是利用数学计算;

#include <iostream>
#include <cmath>

using namespace std;
//initial value of sum is 1 which correspond to (0,0)
int find_index(const int &n,int &sum){
	int i=0;
	while(1){
		int a = 4*i;
		sum += a;
		if(sum > n){
			sum -= a;
			break;
		}
		i++;
	}
	return i;
}

//the value of x is greater or equal to 1
int find_index(const int &n){
	int x = (sqrt(2*n-1)-1)/2+1;
	return x;
}

int find_position(int &remain,int &x){
	int y = 0;
	if(!remain){     //on the boundary
		y = 1-x;
		x = 0;
		return y;
	}
	if(x ==1){        //the length is 1
		if(remain == 2)
		    x = -1;
		else if(remain == 3){
			x = 0;
			y =1;
		}
	}else if (remain == 2)   //the length is greater than 1
	    x = -x;
	else if(remain > 2){
		int i = (remain - 2)/4+1;
		remain -= 2+4*(i-1);
	    switch (remain){
		    case 0:{
		    	x = i-x-1;
		    	y = 1-i;		    		 
		    	break;
		    }
            case 1:{
            	x = x-i;
            	y = i;
            	break;
            }
		    case 2:{
		    	x = x-i;
		    	y = -i;
			    break;
		    }
		    case 3:{
		    	x = i-x;
		    	y = i;
		    	break;
		    }
		}
	}		
    return y;
}

int main()
{
	int n=0;
	while(n++ <30){
		int x,sum,y,remain;
		x = find_index(n);
		sum = 1+2*x*(x-1);
		remain = n-sum; 
        y = find_position(remain,x);
		cout <<'(' <<x <<',' <<y <<')' <<endl;
	}
	cout <<"teset end!"   <<endl;
	return 0;
}

点赞