[LeetCode] Bulb Switcher
There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it‘s off or turning off if it‘s on). For the i-th round, you toggle every i bulb. For the n-th round, you only toggle the last bulb. Find how many bulbs are on after n
Example:
Input: 3 Output: 1 Explanation: At first, the three bulbs are [off, off, off]. After first round, the three bulbs are [on, on, on]. After second round, the three bulbs are [on, off, on]. After third round, the three bulbs are [on, off, off]. So you should return 1, because there is only one bulb is on.
分析:這個題目給了我們n個燈泡,每個燈泡有兩個狀態:開或關。初始都為關,然後經過n次循環,第i次循環就將第1*i、2*i、3*i...個燈泡轉換狀態。求n次之後,有多少個燈泡狀態為開。
還是先枚舉個小例子來分析下,比如只有5個燈泡的情況,‘X‘表示亮,‘√’表示滅,如下所示:
初始狀態: X X X X X
第一次: √ √ √ √ √
第二次: √ X √ X √
第三次: √ X X X √
第四次: √ X X √ √
第五次: √ X X √ X
方法1:根據題意分析,很容易想到用兩個循環來做,外循環用來循環次數,內循環用來改變燈泡的狀態。這裏用0表示關,1表示開。代碼如下:
1 public int bulbSwitch(int n) { 2 int[] bulbs = new int[n]; 3 for ( int i = 0 ; i < n; i ++ ){ 4 for ( int j = i ; j < n ; j=j+i+1 ) 5 bulbs[j] = bulbs[j]==1?0:1; 6 } 7 int sum = 0; 8 for ( int i : bulbs ) sum+=i; 9 return sum; 10 }
思路和代碼是正確的,但是時間復雜度太高,提交之後顯示超時了,因此換了其他的解法。
方法2:參考@Grandyang的解題思路,整理如下:研究一下燈泡狀態變化的規律,發現對於第n個燈泡,當次數是n的因子的時候,狀態會改變,也就是n可以被i整除的時候改變狀態。例如當n=36時,因子對有(1,36)(2,18)(3,12)(4,9)(6,6)。對於(1,36),第1次循環改變之後第36次循環又改變回來了,所以這個因子對實際對狀態並沒有發生改變,還是關狀態。只有(6,6)這個因子本質上改變了燈泡的狀態。因此我們只要尋找<=n的完全平方數就可以了。這裏可以用暴力方法來尋找,代碼如下:
1 public int bulbSwitch(int n) { 2 int res = 1; 3 while ( res * res <= n ) res++; 4 return res-1; 5 }
提交成功,時間為1ms,已經時很數學的方法了。
方法3:還有一種更簡單的方法,直接對n求開方,得到的數就是n以內的完全平方數。剛開始還挺難理解的,被同學一句話點醒,因為比sqrt(n)小的整數i,其i^2一定小於n,所以直接返回sqrt(n)就可以了。代碼就不放上去了,估計0ms。
總結一下,數學真美。
[LeetCode] Bulb Switcher