一个正数如果顺着和反过来都是一样的(如13431,反过来也是13431),就称为回文数。约束:回文数不能以0开头。 最小回文数是1。
思路1:
许多朋友(包括我自己)一开始就思考使用循环:从1开始,判断该数是否是回文数,然后用一个计数器记下回文数,一直到计数器得到N,返回第N个回文数。比较常用的是以下这种方法来判断是否回文数:
-
static boolean isPN(int num)
-
{
-
int o = num;
-
int tmp = 0;
-
-
//使用循环把数字顺序反转
-
while(num != 0)
-
{
-
tmp *= 10;
-
tmp += num % 10;
-
num /= 10;
-
}
-
-
//如果原始数与反转后的数相等则返回true
-
if(tmp == o)
-
return true;
-
return false;
-
}
这种思路的确可得到正确结果,但随着用来测试的N的增大,效率的问题就浮现了。因为是一重 环,效率是O(n)。所以当N非常大时,所花的时间还是十分大的。
思路2:
回文数的个数其实是有规律的。如:
1位回文数: 9个
2位回文数: 9个
3位回文数: 90个
4位回文数: 90个
5位回文数: 900个
6位回文数: 900个
…
我们看到9、90、900,是不是很有规律,那是什么原因?很简单,我们把回文数拆开两半 [123321]来看。两半的变化一样的,那我们只算其中一半就行了。首位不能是0,所以左半最小为 100,最大为999,共有999-100+1=900个,如此类推。
所以我们可以基于以下原则:
1、 回文数的数位每增长2,回文数的个数为原来的10倍。如从个位回文数到百位回文数,个数 从9个变为90个。
2、 个位回文数的个数是9,1、2、3、…、9。
总之理解原理后一切好办,步骤就偷懒不写了,看代码吧!
核心代码:
-
static long find(int index)
-
{
-
int count = 0;
-
int number = 9; //记录数位上的回文数,如个位回文数为9
-
int w = 0; //记录数位
-
-
long half; //保存回文数的左半边的结果
-
long h = 1; //回文数的左半边的起始基数
-
long res; //结果
-
-
while(true)
-
{
-
if(w > 0 && w%2 == 0)
-
{ //每进两个数位,回文数乘以10
-
number *= 10;
-
}
-
w++; //数位加一
-
if(count + number > index) //回文数大于查找的回数,跳出
-
break;
-
-
count += number; //回文数加上当前数位上的回文数
-
}
-
-
index -= count; //在当前数位上的位置。如w=5,index=50,则万位上的第50个回文数是我们所求
-
-
for(int i = 0; i < (w-1) / 2; i++)
-
{ //求回文数的左半边的基数,如回文数在万位上,则为100
-
h *= 10;
-
}
-
-
half = h + index; //回文数的左半边,如100 + 50 = 150
-
-
res = half;
-
-
if(w%2 != 0) //如果为奇数,则中间那个数不必算入右半边了!
-
half /=10;
-
-
while(half != 0)
-
{ //拼接回文数
-
res = res *10 + half % 10;
-
half /= 10;
-
}
-
return res;
-
}
本文思想转自
阅读(1899) | 评论(0) | 转发(0) |