每日演算法系列【LeetCode 319】燈泡開關

  • 2020 年 3 月 12 日
  • 筆記

題目描述

初始時有 個燈泡關閉。第 輪,你打開所有的燈泡。第 輪,每兩個燈泡你關閉一次。第 輪,每三個燈泡切換一次開關(如果關閉則開啟,如果開啟則關閉)。第 輪,每 個燈泡切換一次開關。對於第 輪,你只切換最後一個燈泡的開關。找出 輪後有多少個亮著的燈泡。

示例1

輸入:  3  輸出:  1  解釋:  初始時, 燈泡狀態 [關閉, 關閉, 關閉].  第一輪後, 燈泡狀態 [開啟, 開啟, 開啟].  第二輪後, 燈泡狀態 [開啟, 關閉, 開啟].  第三輪後, 燈泡狀態 [開啟, 關閉, 關閉].    你應該返回 1,因為只有一個燈泡還亮著。

題解

首先有 個燈泡,假設編號為 到 。第 輪,所有編號是 的倍數的燈泡被開關了一次。第 輪,所有編號是 的倍數的燈泡被開關了一次。類推下去,第 輪,所有編號是 的倍數的燈泡被開關了一次。

綜上,對於編號為 的燈泡來說,它最終被開關的次數取決於 有幾個因數。如果有奇數個因數,那麼它最後就是開著的,否則就是關著的。

那麼我們有一個定理:如果一個正整數有奇數個因數,那麼它一定是完全平方數

最淺顯的證明就是,一個數 的因數按照從小到大排個序,首尾兩兩一對之積一定等於 。而如果因數只有奇數個,最中間一個因數 只會出現一次,那麼 。

嚴格證明也不難,首先將 質因數分解為:

那麼 的因數個數就是:

因為 的因數個數是奇數,所以任意 必定是奇數,即任意 必定是偶數。

那麼 就可以寫作:

這就證明了 一定是一個完全平方數。

所以問題就轉化為了求 到 之間有多少個完全平方數。答案就是 。

在具體實現的時候,為了防止出現浮點數誤差(比如 算出來是 ,取整得到 ),我們可以計算 的結果。

程式碼

c++

class Solution {  public:      int bulbSwitch(int n) {          return sqrt(n+0.5);      }  };