目錄
朋友遇到的題目,分享一波。侵刪~
這個題目的難點就在於讀題,如果題目讀明白了,問題自然就解決了。所以在看題的時候要耐心,需要發現除文字描述以外的信息。題目如下
題目
想象一種一維生物,由一系列順序排列的細胞構成(可以理解爲一維數組),細胞只有兩種狀態:活躍或者休眠(取值1或者0)。每經過一代進化,細胞狀態都會發生改變。細胞進化後狀態由當前該細胞狀態和左右相鄰細胞的狀態決定。三個細胞最多有2×2×2=2^3=8種狀態,在這8種狀態下進化後的結果代表一種規則。例如:
上面這類規則表示當前細胞狀態爲休眠且相鄰細胞狀態爲休眠時(000),當前細胞進化後狀態爲休眠(0);當前細胞休眠,左鄰居休眠,右鄰居活躍時(001),進化後狀態爲活躍(1);……;當前細胞活躍,左右鄰居都活躍(111),進化後爲休眠(0).
用8個bit表示的十進制數爲規則編號,總共有0-255共256個規則,例如:
請寫個程序,輸出給定規則編號N下,該生物前K輪的進化狀態。(假設生物的初始狀態固定,且只有最中間一個細胞爲活躍)
class Solution {
public List<String> printStates(int N, int K) {
}
}
例:
30號規則的進化過程如圖所示。
還請讀到這裏的親自己先嚐試理解題目,去儘量多的收集規律和信息。
題目解讀
想要看懂這個題目的重點就在於題目和樣例中給的三幅圖。首先看第一幅
從圖片和題目的描述我們可以知道,每一個方框內有四個小格子(狀態位),黑色代表該位是1,白色代表該位是0;上排三個連續的格子爲當前狀態位,表示當前自己和前後鄰居當前狀態,下邊單獨的格子爲衍生位,表示在當前狀態位是某個值的時候,下一次自己衍生出來是0還是1。
第二幅圖給出了幾個規則關係。
每一個rule代表了一種衍生關係,從讀題的感覺來看,我們需要在這幅圖中找到規律來知道rule0 ~ rule126的排列關係。自己觀察後,確實發現了規律:
給出的所有rule中,當前狀態位的排列都是固定的,都是「“111”,“110”,“101”,“100”,“011”,“010”,“001”,“000”」,而規則編號比如rule30,剛好是將八個格子看成是八個bit後,對應位 置1後得到30,00011110 = 2+4+8+16 = 30;其他規則也同樣遵循這個規律。那可想而知,rule0就是00000000,rule1就是00000001,以此類推。
解題
讀題到這裏,就可以開始構思解題思路了。主要分兩步:1- 構建規則映射; 2- 循環進化得到結果。
題目中描述會給定兩個int值,n代表規則num,k代表迭代輪數。那麼首先我們要通過n構建出一個代表規則的字典,然後讓給定的初始數組按照規則字典進化。
因爲key是固定的「“111”,“110”,“101”,“100”,“011”,“010”,“001”,“000”」,規則字典只需要找到n對應的那幾位爲1即可。代碼如下:
public static Map<String,String> generateRule(int n){
//按照從最低位到最高位的順序排列
String [] values = new String[] {"000","001","010","011","100","101","110","111"};
Map<String,String > rule = new HashMap<>();
for (int i = 0;i < 8;i++){
if ((n & (1 << i)) == 0){
rule.put(values[i],"0");
}else {
rule.put(values[i],"1");
}
}
return rule;
}
一共八位所以循環八次,用1左移0位同n做與運算,如果得到是0,則n的第0位是0,如果結果大於0,則該位爲1.
得到規則映射後,進入進化階段:
public static List<String> printStates(int n,int k){
List<String> result = new ArrayList<>();
Map<String,String> rule = generateRule(n);
String [] current = new String[31];
String [] help = new String[31];
//set default values
for (int i = 0; i < current.length; i++){
if (i == 15){
current[i] = "1";
}else {
current[i] = "0";
}
}
result.add(Solution.toString(current));
String varifyValue = "";
for (int j = 0; j < k;j++){
for (int i = 0; i < current.length; i++){
if (i == 0){
varifyValue = current[current.length - 1] + current[0] + current[i + 1];
}else if (i == current.length - 1){
varifyValue = current[i - 1]+ current[i] + current[0];
}
else {
varifyValue = current[i - 1] + current[i] + current[i + 1];
}
help[i] = rule.get(varifyValue);
}
current = help.clone();
result.add(Solution.toString(help));
}
return result;
}
public static String toString(String [] strs){
String res = "";
for (String s : strs){
res += s;
}
return res;
}
進化階段需要注意的就是邊界值了,從樣例圖中可以看到,第一個一維生物的進化是以最後一個單位作爲左鄰居的,而最後一個一維生物是以第一個單位作爲右鄰居的(請回看題目樣例中的規則和衍生結果),除了這兩種情況以爲,每次的key等於前中後的組合值作爲key去rule map中取值即可。每次迭代的結果存放到List中等待返回。
最終代碼運行結果截圖和樣例對比如下
跟同事聊的過程中同事點撥,當前狀態位中的「“111”,“110”,“101”,“100”,“011”,“010”,“001”,“000”」就是7 ~ 0的二進制排列。
這道題目的實現難度可以說幾乎沒有,但是在面試的緊張狀態下很好的理解題目,從給出的信息中挖掘文字描述之外的信息,這方面考的很好了。