最近看到一个我觉得非常有意思的题目,关于“回型”存储的题目
网上有一些实现方法
这和大家分享一下我的思路和实现方法:
小弟学识浅薄,有不妥的地方,还请各位大神指教!!!!
1. 问题描述:
一组连续的自然数,“回型”的存放入一个n*n的二维数组中,求二维数组中任意坐标的存储的值
例如:存放入一个4*4的二维数组中:
传统解决方法:
先将这串连续的自然数按照规定,存入二维数组,然后再使用传统的访问二维数组的方法访问(nums[ ][ ])坐标对应的位置存储的值
缺点:在只求元素值不需要进行数组存储的情景中,当二维数组的大小非常大时(例如:存入1000 0000*1000 0000的二维数组中),可能会导致内存的溢出,即使内存足够用,这种方法也变得非常的低下,极大的浪费内存空间。
我的思路:
概述:由于这里不需要实现二维数组的物理存储,所以可以通过更为高效的直接“计算”来代替传统的存储后访问,解决了在存储超级大的二维数组时内存不够用的问题(前提是不需要存储的情况)
计算思路:
1.根据目标坐标,计算在存储的二维数组中的所在“圈数”(例如:上述的4*4的案例中,13,14,15,16为第二圈)
注意:为了好判断,这里将二维数组按中心点划分为了四个区,如图:
2.1根据计算得出的圈数,计算该圈的起始的第一个数*(例如:1是第一圈的起始数,13是第二圈的起始数)*
2.2根据计算得出的圈数,计算目标元素在该圈中的位置(例如:14在第二圈中的位置是2)
注意:这个起始数的计算,通过观察第二圈的尾数16,起始数13以及上一圈的尾数12,不难发现尾数和起始数及圈数的规律:本圈尾数=4*本圈长度-4+上圈尾数(16=4*2-4+12) 同时,下一圈起始数=本圈尾数+1(13=12+1)
3.根据目标圈的起始数及目标元素在圈中的位置,计算最终的元素值(例如:15=13+3-1)
代码实现:
回型类的实现:
/**
*
* @author Lee.J.H 李健浩
*
*/
public class HuiXing {
private Long length;//回型存放的数组的规模 n*n
/**
* 该回型存放的数组的圈数
* 长度为基数的规模最内圈为n*n一个数,也算做一个内圈
* 例如:5*5的回型 圈数为:5/2+1 第三圈为5*5=25一个数
*/
private Long Cirs;
public HuiXing(Long length){
this.length=length;
//计算圈数,向上取整
this.Cirs=(long) Math.ceil(new Double(this.length)/2);
}
/**
* 根据所在圈数,计算本圈的第一个数
*
* @param cirNum 0表示最外圈 1...n表示内部第1...n圈
* @return 如果目标圈数合法,返回目标圈的第一个数,否则抛出自定义异常
* @throws OutOfCirNumberException 目标圈超过实际的圈数异常
*/
private Long getFirstOfCir(long cirNum) throws OutOfCirNumberException{
Long temp=0l;
Long len=this.length;
if(cirNum>this.Cirs){
//目标圈数超过真实的圈数
throw new OutOfCirNumberException(cirNum,this.Cirs);
}else{
//圈数合法,计算
for(int i=