一路让人蛋疼的面试题
一道让人蛋疼的面试题
昨日看到了两道面试题,有两道,第一道很多人都答出来了,第二道却鲜有人回答。我本人最近在学习php,所以本文以php为基础带来今天带来第二道的分析。
附两道面试题:
1:大厅里有100盏灯,每盏灯都编了号码,分别为1-100。每盏灯由一个开关来控制。(开关按一下,灯亮,再按一下灯灭。开关的编号与被控制的灯相同。)开始时,灯是全灭的。现在按照以下规则按动开关。
第一次,将所有的灯点亮。
第二次,将所有2的倍数的开关按一下。
第三次,将所有3的倍数的开关按一下。
以此类推。第N次,将所有N的倍数的开关按一下。
问第100次按完以后,大厅里还有几盏灯是亮的。
2:有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。
第一道比较简单不多说了,第二道看着就让人头疼。
简单分析一下这道题。
从题本身来看,貌似同时考虑五个蚂蚁的位置着实让人摸不着头脑。所幸题的最后一句还是很有用的,所有蚂蚁都离开木杆的最大时间和最小时间。将细杆作为一个横向的坐标轴。蚂蚁位置都已经给出。当最后离开的蚂蚁的位置=27的时候,所有蚂蚁离开木杆。(这貌似是废话。)
每秒1米,这样的题设足够让人舒服。毕竟在此处蚂蚁运动的时间数值上等于蚂蚁运动的路程的数值。(如果考虑所有蚂蚁离开木杆还继续保持原有速度运动的话)。并且它们是同时运动。
蚂蚁的运动方向只有两个,向左或向右。考虑到坐标轴的实际情况,如果我们假设向右移动为1,那么等价向左移动为-1。在计算机的二元世界这一步考虑是非常重要的。
好了,前面是铺垫,不管您看懂看不懂,下面是更加重点的内容。
求最大时间和最小时间,就像我们在一堆数里面找最大数和最小数一样,这种事情应该不是很难。关键是找到最后做比较的时间。 时间和什么有关系?从题设来看,只应该和初始每只蚂蚁的运动状态有关。至于期间某个时刻某只蚂蚁的运动状态我们有必要纠结么?没必要。那样只会将问题复杂化。
蚂蚁初始状态有几种?2^5=32种。显然这32种每种花费时间都要算,利用一个简单的循环就可以了。
关注蚂蚁运动状态无非两个变量:位置和方向。因而在此处我简单引入两个数组 $arr和$b 。前者用来描述某个点的当前位置,后者用来当前方向。 $b[i]
如前面所描述的,取值只应该是-1或者1。
考虑到这里,我们就可以捋顺思路,给数组'$arr'和'$b'赋予一个初始值。利用时间'$i'做循环,每一秒每只蚂蚁移动后,当'$arr[$k]==$arr[$k-1]'时,改变相匹配的状态值'$b[k]'的值。 当所有的'$arr'的'value'=27时,停止循环,返回'$i'。其中用了大量的循环遍历。当然为了简便,当'$arr[$k]'不再杆子上时,可以利用unset()函数将其删除。最后判断'$arr'为空就可以结束循环。
讲完主体内容,我们还必须处理一个小细节,如何生成描述蚂蚁运动状态的数组"$b"?
总不能手动生成吧,5只蚂蚁32种情况,10只蚂蚁1024种情况手动生成着实蛋疼。但你明明又知道生成32个数组,不能不利用。因而我们很容易想到将十进制数转化为长度为5的二进制数。再将这个二进制数中的0替换为-1。将替换后的字符串转化为数组。
贴上相应代码:
<span style="color: #000000;">php</span><span style="color: #0000ff;">for</span>(<span style="color: #800080;">$j</span>=0;<span style="color: #800080;">$j</span>$j++<span style="color: #000000;">){ </span><span style="color: #800080;">$var</span>=<span style="color: #008080;">sprintf</span>("%05b", <span style="color: #800080;">$j</span><span style="color: #000000;">); </span><span style="color: #800080;">$var</span>=<span style="color: #008080;">str_replace</span>('1', '1|', <span style="color: #800080;">$var</span><span style="color: #000000;">); </span><span style="color: #800080;">$var</span>=<span style="color: #008080;">str_replace</span>('0', '-1|', <span style="color: #800080;">$var</span><span style="color: #000000;">); </span><span style="color: #800080;">$b</span>=<span style="color: #008080;">explode</span>('|',<span style="color: #800080;">$var</span><span style="color: #000000;">); </span><span style="color: #800080;">$res</span>=getRes(<span style="color: #800080;">$b</span><span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$min</span><span style="color: #000000;">)) { </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$res</span>$min<span style="color: #000000;">) { </span><span style="color: #800080;">$min</span>=<span style="color: #800080;">$res</span><span style="color: #000000;">; } }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #800080;">$min</span>=<span style="color: #800080;">$res</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$max</span><span style="color: #000000;">)) { </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$res</span>><span style="color: #800080;">$max</span><span style="color: #000000;">) { </span><span style="color: #800080;">$max</span>=<span style="color: #800080;">$res</span><span style="color: #000000;">; } }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #800080;">$max</span>=<span style="color: #800080;">$res</span><span style="color: #000000;">; } </span><span style="color: #008080;">print_r</span>(<span style="color: #800080;">$b</span><span style="color: #000000;">); </span><span style="color: #0000ff;">echo</span> "此次结果是".<span style="color: #800080;">$res</span>.' $max='.<span style="color: #800080;">$max</span>.' $min='.<span style="color: #800080;">$min</span><span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "<hr>"<span style="color: #000000;">;}</span><span style="color: #0000ff;">echo</span> "最大值是".<span style="color: #800080;">$max</span>."最小值是".<span style="color: #800080;">$min</span><span style="color: #000000;">;</span><span style="color: #008000;">//</span><span style="color: #008000;">获得某种情况下的时间</span><span style="color: #0000ff;">function</span> getRes(<span style="color: #800080;">$b</span><span style="color: #000000;">){ </span><span style="color: #800080;">$arr</span>=<span style="color: #0000ff;">array</span>(3,7,11,17,23<span style="color: #000000;">); </span><span style="color: #0000ff;">for</span>(<span style="color: #800080;">$i</span>=1;<span style="color: #800080;">$i</span>$i++<span style="color: #000000;">){ </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$arr</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$k</span> => <span style="color: #800080;">$val</span><span style="color: #000000;">) { </span><span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>]=<span style="color: #800080;">$val</span>+<span style="color: #800080;">$b</span>[<span style="color: #800080;">$k</span><span style="color: #000000;">]; </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>]==@<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>-1<span style="color: #000000;">]) { </span><span style="color: #800080;">$b</span>[<span style="color: #800080;">$k</span>]=-<span style="color: #800080;">$b</span>[<span style="color: #800080;">$k</span><span style="color: #000000;">]; </span><span style="color: #800080;">$b</span>[<span style="color: #800080;">$k</span>-1]=-@<span style="color: #800080;">$b</span>[<span style="color: #800080;">$k</span>-1<span style="color: #000000;">]; } </span><span style="color: #0000ff;">if</span> ((<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>]>=27)||(<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>])) { <span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span><span style="color: #000000;">]); } } </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$arr</span><span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$i</span><span style="color: #000000;">; } }}</span>
这是按套路出牌的,循规蹈矩,一步一步走过来,但确实也十分辛苦。
------------------------------------- ---华丽的分隔线-------------------------------------------------------------------------------------------
在我一本正经地胡说八道后,就没有更加好的想法?
那就是相遇的时候,两只蚂蚁开始掉头。如果不掉头直接走呢?和他们掉头后有什么差别?结果是没有差别!每只蚂蚁开头拿一个接力棒,碰头后,两人交换接力棒,虽然蚂蚁掉头了,但接力棒可是一直往初始方向走哦~所以解题前景变得无比明朗。知道某只蚂蚁的初始状态,就知道他开始拿的接力棒最后走了多久!至于接力棒是不是亲生的,那你管哩。反正最后一个接力棒离开杆子,最后一只蚂蚁也离开杆子。
因而获得某种初始状态下的时间还可以这样写:
<span style="color: #0000ff;">function</span> getRes(<span style="color: #800080;">$b</span><span style="color: #000000;">){ </span><span style="color: #800080;">$arr</span>=<span style="color: #0000ff;">array</span>(3,7,11,17,23<span style="color: #000000;">); </span><span style="color: #0000ff;">for</span>(<span style="color: #800080;">$i</span>=1;;<span style="color: #800080;">$i</span>++<span style="color: #000000;">){ </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$arr</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$k</span> => <span style="color: #800080;">$val</span><span style="color: #000000;">) { </span><span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>]=<span style="color: #800080;">$val</span>+<span style="color: #800080;">$b</span>[<span style="color: #800080;">$k</span><span style="color: #000000;">]; </span><span style="color: #0000ff;">if</span> ((<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>]>=27)||(<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span>])) { <span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$arr</span>[<span style="color: #800080;">$k</span><span style="color: #000000;">]); } } </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$arr</span><span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$i</span><span style="color: #000000;">; } }}</span>
------------------------------------- ---华丽的分隔线-------------------------------------------------------------------------------------------
当然问题可以更加简化,连上面的代码都用不到了。
通过上面分析可以看做每只蚂蚁直接走互不影响。到最后求最大值最小值的时候实际上可以先算出每只蚂蚁到两端的距离。形成五组数字。(3,24),(7,20),(11,16),(10,17),(4,23)在五组数每组数中较小值形成的5个数中最大的一个是最后结果的最小值。 五组数每组数中较大的5个数中最大的那个是结果的最大值。很容易看出来是11和24。为什么呢?典型的木桶效应啊。最后一只蚂蚁走出去了才能算完成整个事情。五只蚂蚁全部最短路径出去,得到结果才可能是最快的,五只蚂蚁全部最长路径出去,耗时才能是最慢的。
ps:应该不会有更快的想法了吧。
最后感谢@randeng在本问题上的指点~
- 7楼gw2010
- 第一题不用编程怎么做?,第二题看到上面的答案了。
- Re: DeanChopper
- @gw2010,不好意思这个我也不清楚。。不过感觉学数学应该会考虑到一些比较简单的东西吧。
- 6楼温柔的意外
- 最短:←3 ←7 ←11 →17 →23,最长:3→ 7→ 11→ ←17 ←23
- 5楼DCD
- 其实没这么麻烦,最小时间,就是最理想状态下的时间,也就是位于11cm的蚂蚁往左走,11秒搞定。,最大时间,其实可以理解为两只蚂蚁碰面后,不是都往反方向走,而是对着穿过去。那么就是3cm的蚂蚁往右走,27-3=24秒。
- 4楼Ariex
- 第一个是计算哪些数分解出来的因数总数是奇数么?
- Re: MrNice
- @Ariex,对的,好像分析到最后就是完全平方数了
- Re: DeanChopper
- @Ariex,这是最直观的想法,我也是这么考虑的。不知道还有什么好的算法
- 3楼randeng
- 第二题,《编程之美》上有。两只蚂蚁碰头转向,你可以看做两只蚂蚁错身而过,互相影响。有两只蚂蚁A, B,A-gt;,Blt;-,当他们相遇后,Alt;-, B-gt;,你可以把相遇后的A作为相遇前B,B作为相遇前A,这样他们还是在继续向前移动。所有只需要遍历一次数组,分别求出运动时间,找出大小就行了。
- Re: DeanChopper
- @randeng,万分感谢,我一定会再看看的~~
- 2楼笑对当空
- 感觉不太对啊 我是用笨办法 模拟每一只蚂蚁的行走轨迹 发现 最快的才23 最慢的才35和你的两头距离最远多少就走了多少差距有点大啊,难道我算错了?
- Re: DeanChopper
- @笑对当空,最短的情况,前三只蚂蚁往左走,后两只往右走。耗时11秒。最慢的情况,全部往右走,耗时24秒。
- 1楼风生水起
- 第二题直接认为5只蚂蚁互相没有影响,最小时间就是所有蚂蚁都超最近的那头走,最大时间是所有蚂蚁都超最远的那头走,写程序就是判断每只蚂蚁离两头的具体,最小时间取最近中最大的((所以是11),最大时间是取最远中最大(等于24)。一次循环就可以
- Re: DeanChopper
- @风生水起,实际分析到最后确实是这样的。更像脑急转玩儿了。主要是想到5只蚂蚁没影响这一步很不容易,否则就会像我上面第一种方法一样费力不讨好。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

「你的組織要求你更改PIN訊息」將顯示在登入畫面上。當在使用基於組織的帳戶設定的電腦上達到PIN過期限制時,就會發生這種情況,在該電腦上,他們可以控制個人設備。但是,如果您使用個人帳戶設定了Windows,則理想情況下不應顯示錯誤訊息。雖然情況並非總是如此。大多數遇到錯誤的使用者使用個人帳戶報告。為什麼我的組織要求我在Windows11上更改我的PIN?可能是您的帳戶與組織相關聯,您的主要方法應該是驗證這一點。聯絡網域管理員會有所幫助!此外,配置錯誤的本機原則設定或不正確的登錄項目也可能導致錯誤。即

Windows11將清新優雅的設計帶到了最前沿;現代介面可讓您個性化和更改最精細的細節,例如視窗邊框。在本指南中,我們將討論逐步說明,以協助您在Windows作業系統中建立反映您的風格的環境。如何更改視窗邊框設定?按+開啟“設定”應用程式。 WindowsI前往個人化,然後按一下顏色設定。顏色變更視窗邊框設定視窗11「寬度=」643「高度=」500「>找到在標題列和視窗邊框上顯示強調色選項,然後切換它旁邊的開關。若要在「開始」功能表和工作列上顯示主題色,請開啟「在開始」功能表和工作列上顯示主題

預設情況下,Windows11上的標題列顏色取決於您選擇的深色/淺色主題。但是,您可以將其變更為所需的任何顏色。在本指南中,我們將討論三種方法的逐步說明,以更改它並個性化您的桌面體驗,使其具有視覺吸引力。是否可以更改活動和非活動視窗的標題列顏色?是的,您可以使用「設定」套用變更活動視窗的標題列顏色,也可以使用登錄編輯程式變更非活動視窗的標題列顏色。若要了解這些步驟,請前往下一部分。如何在Windows11中變更標題列的顏色? 1.使用「設定」應用程式按+開啟設定視窗。 WindowsI前往“個人化”,然

您是否在Windows安裝程式頁面上看到「出現問題」以及「OOBELANGUAGE」語句? Windows的安裝有時會因此類錯誤而停止。 OOBE表示開箱即用的體驗。正如錯誤提示所表示的那樣,這是與OOBE語言選擇相關的問題。沒有什麼好擔心的,你可以透過OOBE螢幕本身的漂亮註冊表編輯來解決這個問題。快速修復–1.點選OOBE應用底部的「重試」按鈕。這將繼續進行該過程,而不會再打嗝。 2.使用電源按鈕強制關閉系統。系統重新啟動後,OOBE應繼續。 3.斷開系統與網際網路的連接。在脫機模式下完成OOBE的所

工作列縮圖可能很有趣,但它們也可能分散注意力或煩人。考慮到您將滑鼠懸停在該區域的頻率,您可能無意中關閉了重要視窗幾次。另一個缺點是它使用更多的系統資源,因此,如果您一直在尋找一種提高資源效率的方法,我們將向您展示如何停用它。不過,如果您的硬體規格可以處理它並且您喜歡預覽版,則可以啟用它。如何在Windows11中啟用工作列縮圖預覽? 1.使用「設定」應用程式點擊鍵並點選設定。 Windows按一下系統,然後選擇關於。點選高級系統設定。導航至“進階”選項卡,然後選擇“效能”下的“設定”。在「視覺效果」選

在Windows11上的顯示縮放方面,我們都有不同的偏好。有些人喜歡大圖標,有些人喜歡小圖標。但是,我們都同意擁有正確的縮放比例很重要。字體縮放不良或圖像過度縮放可能是工作時真正的生產力殺手,因此您需要知道如何自訂以充分利用系統功能。自訂縮放的優點:對於難以閱讀螢幕上的文字的人來說,這是一個有用的功能。它可以幫助您一次在螢幕上查看更多內容。您可以建立僅適用於某些監視器和應用程式的自訂擴充功能設定檔。可以幫助提高低階硬體的效能。它使您可以更好地控制螢幕上的內容。如何在Windows11

螢幕亮度是使用現代計算設備不可或缺的一部分,尤其是當您長時間注視螢幕時。它可以幫助您減輕眼睛疲勞,提高易讀性,並輕鬆有效地查看內容。但是,根據您的設置,有時很難管理亮度,尤其是在具有新UI更改的Windows11上。如果您在調整亮度時遇到問題,以下是在Windows11上管理亮度的所有方法。如何在Windows11上變更亮度[10種方式解釋]單一顯示器使用者可以使用下列方法在Windows11上調整亮度。這包括使用單一顯示器的桌上型電腦系統以及筆記型電腦。讓我們開始吧。方法1:使用操作中心操作中心是訪問

Windows上的啟動過程有時會突然轉向顯示包含此錯誤代碼0xc004f069的錯誤訊息。雖然啟動程序已經聯機,但一些運行WindowsServer的舊系統可能會遇到此問題。透過這些初步檢查,如果這些檢查不能幫助您啟動系統,請跳到主要解決方案以解決問題。解決方法–關閉錯誤訊息和啟動視窗。然後,重新啟動電腦。再次從頭開始重試Windows啟動程序。修復1–從終端啟動從cmd終端啟動WindowsServerEdition系統。階段–1檢查Windows伺服器版本您必須檢查您使用的是哪種類型的W
