問題描述:
算法分析:
s1:層數對齊:分別求兩個數所在的層(l1,l2),把層數大的(假設l2>l1)先往上找父節點,從而對齊到l1層;
s2:兩個數同時往上找, 直到找到公共的父節點(一定能找到,最壞情況下是0), 算法結束。
因此算法的核心就變成了如何找父節點, 求父節點的分析:
求父節點的時候,總是發現沒有規律可循, 最重要的原因就是樹中節點序號的增加是一個s型的路線,那么我們是利用這種特殊性
(s型),還是去除這種特殊性;我暫時沒有發現如何利用這種特殊性, 所以我就先把樹中節點的序號按從左到右的順序遞增,發現這樣求
父節點的規律就很明顯了,所以就采用了"去除這種特殊性"的方法。那么如何去除:每行中間位置上的節點的序號是有規律的,所以通過中
間數,和求得的父節點序號(不是真實的父節點序號, 如:17/3 == 5, 但實際上17的父節點是11,不是5),得到真實的父節點序號。
用一個例子來說明, 比如求17的父節點序號:
先直接求父節點序號(假的):17/3==5,求父節點所在層(2層)中間節點的序號為8, 所以真實的父節點序號是:8*2-5=11]
//File: Solution.java //Author: lxw //Time: 2014-10-09 //Usage: Get the common ancestor. //Method: Align the layers of the 2 numbers. Decrease both of the layers to find the common ancestor.
//NOTE that each time the layer is decreased, we need to convert the number. import java.util.*; public class Solution{ //I really do not think this function uses a good altorithm. private static int getLayer(int num){ int res = 1; int last = 0; int next = 0; if(num == 0){ return 0; } last = (int)((Math.pow(3, res) - 3.0) / 2.0); while(true){ next = (int)((Math.pow(3, res+1) - 3.0) / 2.0); if(num > last && num <= next){ return res; } ++res; last = next; } } private static int getMid(int layer){ if(layer > 0){ int sum = 0; for(int i = 1; i < layer; ++i){ sum += Math.pow(3, i); } sum += (int)((Math.pow(3, layer) + 1.0) / 2.0); return sum; } else{ return 0; } } //num2Lay >= num1Lay private static int getCommon(int num2Lay, int num1Lay, int num2, int num1){ //層數對齊 while(num1Lay != num2Lay){ if(num2 % 3 == 0){ --num2; } num2 /= 3; --num2Lay; //Each time the layer is decreased, we need to convert the number num2 = 2 * getMid(num2Lay) - num2; } //一起往上找父節點 if(num2 == num1){ return num1; //final answer } else{ while(num2 != num1){ if(num2 % 3 == 0){ --num2; } if(num1 % 3 == 0){ --num1; } num2 /= 3; num1 /= 3; //Since num2Lay == num1Lay, only one of them is needed. //--num2Lay; --num1Lay; //Each time the layer is decreased, we need to convert the number. int mid = 2 * getMid(num1Lay); num2 = mid - num2; num1 = mid - num1; } return num1; } } public static void main(String[] args){ Scanner in = new Scanner(System.in); int num1, num2, num1Lay, num2Lay; while(true){ System.out.println("Input:"); num1 = in.nextInt(); num2 = in.nextInt(); num1Lay = getLayer(num1); num2Lay = getLayer(num2); if(num1Lay < num2Lay){ System.out.println(getCommon(num2Lay, num1Lay, num2, num1)); } else{ System.out.println(getCommon(num1Lay, num2Lay, num1, num2)); } System.out.println(); } } }
寫在這里, 如果有人看到話, 希望各位能夠互相交流. 肯定有更好的方法, 希望各位不吝賜教.