[算法]由日期格式函数产生的若干思考 y * 512 + m * 32 + d
完整源码
// Java Code
public class TestDate{
public static void main(String args[]){
int m = Integer.parseInt(args[0]);
int d = Integer.parseInt(args[1]);
int y = Integer.parseInt(args[2]);
Date date = new Date(m,d,y);
System.out.println(date);
}
}
class Date{
private final int value;
public Date(int m,int d,int y){
value = y*512+m*32+d;
}
public int month(){
return (value/32)%16;
}
public int day(){
return value%32;
}
public int year(){
return value/512;
}
public String toString(){
return month()+"/"+day()+"/"+year();
}
}
代码说明
value = y * 512 + m * 32 + d;
value = y * 2^9 + m * 2^5+ d;
m = (value / 32) % 16;
// 除以32后,剩下 y*2^4 + m(d消掉了,2^4 = 2^9 / 2^5),接着再用16(即2^4)取余,得m
d = value % 32;
// 用32取余自然剩下余数d
y = value / 512;
// 用512除法自然得到y
// 简单猜测计算了一下,输入条件应该限定在:m 取值范围在[0,15] (2^4-1), d 取值范围在[0,31] (2^5-1).
用例测试
分别取了边界以及边界+1的几组用例来测m([0,15] )、d([0,31])的取值范围.
Input | Output | Test Result |
---|---|---|
7 11 2015 | 7/11/2015 | √ |
7 11 0 | 7/11/0 | √ |
0 11 2015 | 0/11/2015 | √ |
7 0 2015 | 7/0/2015 | √ |
15 11 2015 | 15/11/2015 | √ |
7 31 2015 | 7/31/2015 | √ |
16 11 2015 | 0/11/2015 | × |
7 32 2015 | 8/0/2015 | × |
我的思考
这种把3个输入运用乘法变成1个数字,再运用适当的规则拆回来的思路真是绝顶赞啊! 同时,这种拆的规则也是非常巧妙,我今天算是彻底体会了取余和除法的那种微妙地差别和巧妙地混合使用了,实在开心。
以前遇见过的类似的运算,就是那种取出每个数位上的数字的题目,比如说
2015 = 2*10^3+0*10^2+1*10^1+5*10^0
,需要取出2 0 1 5这几个数字,思路简直异曲同工!上面的代码里会使用512=2^9 32=2^5
的确是为了配合日期格式这一目的;因为数值都不大,边界可以快速手工确定,可以的话我挺想看看严谨的数学推导过程。对于这样的数字来说,+所起到的或许就是抽象意义上的“连接“的作用而非单纯只有数学意义上的求和吧,或者这么说求和是形式而不是目的;
写到这里,我终于想到了那个可能的大话题,或许就是所谓的“进制转换”吧,算法真是很有趣呢!
引用参考
图灵程序设计丛书:算法(第4版) 塞奇威克 (Robert Sedgewick) (作者), 韦恩 (Kevin Wayne) (作者),
谢路云 (译者)