LeetCode_脑筋急转弯
目錄:
- 292.Nim游戲
- 319.燈泡開關
- 777.在LR字符串中叫喚相鄰字符
- 1033.移動石子直到連續
- 1227.飛機座位分配率
- 1503.所有螞蟻掉下來前的最后一刻
292.Nim游戲
思路
如果堆中石頭的數量 nn 不能被 44 整除,那么你總是可以贏得 Nim 游戲的勝利。
推理
讓我們考慮一些小例子。顯而易見的是,如果石頭堆中只有一塊、兩塊、或是三塊石頭,那么在你的回合,你就可以把全部石子拿走,從而在游戲中取勝。而如果就像題目描述那樣,堆中恰好有四塊石頭,你就會失敗。因為在這種情況下不管你取走多少石頭,總會為你的對手留下幾塊,使得他可以在游戲中打敗你。因此,要想獲勝,在你的回合中,必須避免石頭堆中的石子數為 4 的情況。
同樣地,如果有五塊、六塊、或是七塊石頭,你可以控制自己拿取的石頭數,總是恰好給你的對手留下四塊石頭,使他輸掉這場比賽。但是如果石頭堆里有八塊石頭,你就不可避免地會輸掉,因為不管你從一堆石頭中挑出一塊、兩塊還是三塊,你的對手都可以選擇三塊、兩塊或一塊,以確保在再一次輪到你的時候,你會面對四塊石頭。
顯然,它以相同的模式不斷重復 n=4,8,12,16,\dotsn=4,8,12,16,…,基本可以看出是 44 的倍數。
題解C
bool canWinNim(int n){return (n/4==0); }319.燈泡開關
1 分析
1)第j輪的第i個燈泡的狀態判斷方法:
將包含本輪在內的對第i個燈泡的所有操作次數做和,記為Sij。
若Sij為奇數,說明第i個燈泡,經過j輪以后,是亮著的,因為第0輪一定是關閉的。
同理,若Sij為偶數,說明第i個燈泡,經過j輪以后,是關閉的。
所以問題轉變為:
經過n輪,第i個燈泡被操作了奇數次還是偶數次?奇數次則最后是亮的,偶數次則最后是關閉的。
2)觀察:
第j輪操作的燈泡的位置,一定是j的倍數。咱們反向觀察一下:
第1個燈泡在什么時候會被操作?第1輪
第10個燈泡在什么時候會被操作?第1輪,第2輪,第5輪,第10輪
第20個燈泡在什么時候會被操作?第1輪,第2輪,第4輪,第5輪,第10輪,第20輪
說到這里,會立馬發現:第 i 個燈泡只有在第 k 輪會被操作,而 k 一定是 i 的因數。并且 n>=k。所以如果一個數的因數的個數為奇數個,那么它最后一定是亮的,否則是關閉的。
那么問題又轉變了:
什么數的因數的個數是奇數個?
答案是完全平方數。
2 為什么完全平方數的因數的個數是奇數個?
設P,A,B 為正整數,如果 P=A*B,則A和B為P的因數。
P的因數A和B總是成對出現。也就是說他們總是一起為 P 的因數個數做貢獻。但是如果他們相等呢?這個時候他們一起只會為因數的個數貢獻 1。
其次,P=A*A,這種情況對于P來說最多只能出現1次,而這種情況只可能出現在完全平方數中。
所以對于正整數而言,只有完全平方數的因數的個數是奇數個。
綜上所述,所以每個完全平方數就是答案
還可以這樣推導:
對于數k,第i輪被撥一下的條件是k%i==0
所有數k被撥的次數是k的約束的個數
若k=p_1^x p_2^y p_3^z … , 其中p_i為素數,則約數的個數f(k)= (1+x)(1+y)(1+z).
第k個燈亮意味著f(k)為奇數,根據推論3可知,其中的x,y,z…都必須為偶數。
回看,k=p_1^x p_2^y p_3^z … , 說明k是個完全平方數
題解C
int bulbSwitch(int n){return (int)sqrt(n); }777.在LR字符串中叫喚相鄰字符
思路
將 ‘L’,‘R’ 分別理解為一個隊伍中面向左和面向右的人,‘X’ 理解為隊伍中的空擋。可以問自己一個問題,一次移動操作之后有什么是保持不變的? 這是狀態轉換問題中一個很常見的思路。
算法
這道題的 轉換不變性 在于字符串中的 ‘L’ 和 ‘R’ 是不會互相穿插的,也就是隊伍中的人在移動過程中是不能穿過人的。這意味著開始和結束的字符串如果只看 ‘L’ 和 ‘R’ 的話是一模一樣的。
除此之外,第 n 個 ‘L’ 不可能移動到初始位置的右邊,第 n 個 ‘R’ 不可能移動到初始位置的左邊,我們把這個特性稱為 “可到達性“。
根據 轉換不變性 和 可到達性,在算法中可以分別檢查這兩個性質是否滿足。如果都滿足,則返回 True,否則返回 False。
題解Java
class Solution {public boolean canTransform(String start, String end) {if (!start.replace("X", "").equals(end.replace("X", "")))return false;int t = 0;for (int i = 0; i < start.length(); ++i)if (start.charAt(i) == 'L') {while (end.charAt(t) != 'L') t++;if (i < t++) return false; //發現end中L往右移了}t = 0;for (int i = 0; i < start.length(); ++i)if (start.charAt(i) == 'R') {while (end.charAt(t) != 'R') t++;if (i > t++) return false; //發現end中R往左移了}return true;} }1033.移動石子直到連續
思路:
題目看著很繞,其實很簡單,首先排序,排序并不會改變結果,但是我們寫起來更方便一點,然后重新賦值abc
a最小,c最大,因為只能拿兩邊的石頭往中間放,所以最大情況就是一步一步挪,那么就是c-a-2,最小情況多重情況討論即可
三個緊貼著 c-a=2 返回0
其中有兩個緊貼著 返回1
其中有兩個中間空了一格 返回 1
最小移動次數最大是2 就是兩邊分別往中間放
題解Java
class Solution {public int[] numMovesStones(int a, int b, int c) {int[] arr = new int[]{a, b, c};Arrays.sort(arr);a=arr[0];b=arr[1];c=arr[2];int min = 0;if (c - a == 2) min = 0;else if (b - a == 1 || c - b == 1) min = 1;else if (b - a == 2 || c - b == 2) min = 1;else min = 2;return new int[]{min, c - a - 2};} }1227.飛機座位分配率
思路
設dp[i]為第i個乘客坐在自己的座位上的概率,
初始化dp[1]=1;dp[2]=0.5;
當i=3時:
若第一個人選擇第一個座位,后邊的人的椅子沒有被占用,按照正常順序,第3個人肯定能坐到第3個位置,這個概率是1/3;
若第一個人選擇第二個位置,第二個人發現自己的椅子被占用,他有兩個位置可選,只有選擇第一個位置,第三個人才能坐到自己的位置,根據概率乘法原則,這個概率是1/3 × 1/2;
只有這兩種情況,第3個人才能坐到第三個位置
所以dp[3]=1/3+1/3×1/2
=1/3×(1+1/2)
=1/3×(dp[1]+dp[2])
以此類推,可以推出來:
dp[i]=(1/i)×(dp[1]+dp[2]+…+dp[i-1])
這就是狀態轉移方程
所以說實際上只要n>1,那么結果必是1/2!
題解Java
class Solution {public double nthPersonGetsNthSeat(int n) {if (n == 1) {return 1.0;}double [] dp=new double[n+1];//從下標1開始使用dp[2]=0.5;double sum_dp=1.5;for(int i=3;i<=n;i++){dp[i]=(1.0/(double)i)*sum_dp;sum_dp+=dp[i];}return dp[n];} }1503.所有螞蟻掉下來前的最后一刻
思路
兩個螞蟻相撞之后會互相調頭,其實只要想成如果每只螞蟻都長得一模一樣,那么是不是螞蟻碰撞的調頭 就等于 穿透了?
知道了這一點,那么就可以直接讓螞蟻直接穿透爬行就好了
那么題目就變成了求單只最晚落地的螞蟻,與碰撞無關
題解Java_1
class Solution {public int getLastMoment(int n, int[] left, int[] right) {int max = -1;for(int i = 0; i < left.length;i++){max = Math.max(max,left[i]);}for(int i = 0; i < right.length;i++){max = Math.max(max,n-right[i]);}return max;} }題解Java_2
class Solution {public int getLastMoment(int n, int[] left, int[] right) {int leftMax = Integer.MIN_VALUE;int rightMin = Integer.MAX_VALUE;// 往右走的取最小值for (int item : right) {if (rightMin > item) {rightMin = item;}}// 往左走的取最大值for (int item : left) {if (leftMax < item) {leftMax = item;}}return Math.max(leftMax, n - rightMin);} }總結
以上是生活随笔為你收集整理的LeetCode_脑筋急转弯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode_97.交错字符串_没懂
- 下一篇: LeetCode_每日一题今日份_312