一道樂視網的面試題,求解答?
今天師姐在樂視網面試,遇到一道很難得演算法題,問了好多同學都不會,特地放到知乎上請各位大神解決!開始覺得是動態規劃,但是想了想好像也不是...
這是道數學題,大概說一下。
對於輸入為負數,結果與正數相等,忽略。設輸入為n。
先求出一個p,使得 p*(p-1)/2 &< n &<= p*(p+1)/2 ,也就是說,1加到p剛好大於等於n,少一個就不行。顯然,p是步數的最小值,而1加到p也正是p項和的最大值。設 k=p*(p+1)/2-n ,就是最大值減去輸入值。求p可以直接解二次方程,用double的14位精度應該夠了,或者做一點算術上的修正,複雜度和sqrt相同。然後開始解步數。
顯然k&當k=0時,答案步數就是p。
當k是偶數時,設k=2*r,則把1+2+3+...+p變成1+2+3+...-r+(r+1)+...+p即可,步數為p,顯然最優。當k是奇數時,設k=2*r+1,再次分類。觀察到p*(p+1)-n=k,而k是奇數,所以最大和於目標值奇偶性不同,又翻轉一個數(把1加到p的式子中的一個數從加變成減)奇偶性不變,因此根據p的奇偶性討論現在的最小步數。當p是奇數時,p=2*q+1,p+1是偶數,不可能改變奇偶性,因此最少需要p+2步,式子為1+2+3+...-r+(r+1)+...+p+(p+1)-(p+2),在p*(p+1)/2的基礎上減掉2*r再減掉1,正好p+2步,顯然最優。
當p是偶數時,p=2*q,p+1是奇數,可以改變奇偶性,最小p+1步,式子為1+2+3+...-r+(r+1)+...+q-(q+1)+...+p+(p+1),在p*(p+1)/2的基礎上減2*r,減2*(q+1)再加上p+1=2*q+1,總共減掉2*r+1,正好p+1步。因為2*r+1=k&p/2-1/2&>r,所以不會衝突。
這段討論都是O(1)。討論邊際條件。
1. k偶時r=p, r=k/2&2. k奇時r=p, r=(k-1)/2=k/2-1/2&
總結,單個數字的複雜度完全由開平方算p決定,一般用FPU的話是帶大常數的O(1),應該比樓上O(nlogn)快。
代碼有空再貼,今天晚了。
以上。想成是先跳1,2,3,……n步,這樣就到了的地方;然後挑一些步數,把正著跳變成反著跳,每一次減少的數是2k。由於我們把一個正跳變成反跳,只能減少偶數步,所以最開始的總和必須要跟x的奇偶性相同。這個表達式的奇偶性取決於n對4取模的結果,餘0、餘3的時候是偶數,餘1、餘2的時候是奇數。分別可以寫成:我們再來考慮要回退的數的範圍。為了方便,我們記前面的表達式。如果我們挑了一個奇數,它:
- 位於S(4k+1)與S(4k+2)之間,於是相應的n至少應當是4k+2。我們要回退的範圍是0到4k中的偶數。回退一個數足夠了。
- 位於S(4k+2)與S(4k+5)之間,相應的n至少應當是4k+5。要回退的範圍是0到12k + 10中的偶數。這時候一個就不夠了,6k+5不在範圍內……但是,4k+3和2k+2怎麼樣?如果更小的話,自然也可以表示成4k+3和相應數的和,或者用單個數。
如果我們挑出了一個偶數,它:
- 位於S(4k)與S(4k+3)之間,於是相應的n至少應當是4k+3,要回退的範圍是0到12k+4中的偶數。4k+2,2k,兩個數剛好。更小的數自然也可以表示。
- 位於S(4k+3)與S(4k+4)之間,於是相應的n至少應當是4k+4,要回退的範圍是0到4k+4中的偶數。一個數足夠了。
結論:只要選出符合條件的最小的n,就一定可以跳到這一點上。符合條件是指:S(n) &>= x,且x為奇數是n = 4k + 1或4k + 2,x為偶數時n = 4k + 3或4k + 4。
求n的方法自然是求根公式:
這裡要小心處理的一個坑是當1 + 8x是完全平方數的時候,整個表達式算出的結果是個整數,如果舍入誤差處理不好,往上進了1,就貽笑大方了……所以算出結果之後可以帶回到n(n+1) &>= 2x的表達式當中,檢驗n0和n0-1各自是否符合條件。算出n0之後,再根據x的奇偶性和n0對4取模的結果調整一下就可以輸出了。
最簡單粗暴的方法:bfs…
下面是數學方法,可以視為對@王遠答案的補充,因為我覺得他寫的不夠直觀
首先引入一條引理:1,2,3...p中部分數的和與1到p(p+1)/2之間的整數存在雙射關係,且兩者相等。下圖是p=4時的例子設走p步後到達位置x(p)
則x(p)=a1*1+a2*2+…+ap*p,其中ai為係數要麼取1要麼取-1,取不同的係數對應不同的行動路徑。令sum(p)=1+2+…+p,k(p)=sum-x易知k是個偶數
那麼我們到到達目的地x0隻需保證sum(p)&>x0且k(p)是個偶數,在這個條件下找最小步數,有如下流程步驟1:取整數p滿足
p(p-1)/2&這裡有個問題,我們通過這個演算法得到最小步數p,但我們怎麼保證一定存在一組係數ai使x(p)=x0,即存在一條行動路徑使得p步後可以到達目的地x0。這時,引理就起作用了。
令r=k/2,因為0&<=r&負數可以轉化成等價的正數情況。然後討論正數。
這個問題等價於序列 ?1?2?3?4...?n=k ,?代表正負號,求最小的n。設a為其中正數項的和,b為負數項和。那麼
a-b=(1+n)*n/2 a+b=k兩式相減得
-2b=(1+n)*n/2-k&>=0對於公式 (1+n)*n/2-k要滿足兩個條件
1.值大於等於0 2.值是2的倍數做法就是枚舉,n從1開始枚舉,當滿足上訴兩個條件就停止。
時間複雜度目測sqrt(n)還有更快的,先在O(1)時間裡找到讓等式小於等於0的最大n,然後再從這個n開始枚舉。最後我敢說這是從ACdreamers的博客里看到的原題(UVA10025)QwQ 附鏈接(逃 數學經典題目經過觀察,走 n 步之後能走到的長度是一個差為2的等差數列。
比如:走1步,1=1,可能的目標是 {-1,1}走2步,1+2 = 3, {-3,-1,1,3}
走3步,1+2+3=6, {-6,-4,-2,0,2,4,6}先令 x = abs(x)
設解為n,令y = n(n+1)/2,若 y &> x,且 x 與 y 奇偶性相同,則 n 就是解了吧。譬如,x = 7。則n = 5, 此時y = 15。x = 0 -1 + 2 - 3 +4 + 5 = 7編程細節不討論了。勉強算O(1)?
#include &
#include &
int minStep(int x) {
if (x==0) return 0;
if (x&<0) x=-x;
int n=sqrt(2*x);
while ((n+1)*n/2-x1 || (n+1)*n/2&
沒做出來,es6的bfs留下當參考吧
function bfs(x){
let m=new Set([0]);
for(let i=0;;i++){
let k=new Set();
for(let j of m){
if ((j+i)==x) return i;
if ((j-i)==x) return i;
k.add(j+i);
k.add(j-i);
}
m=k;
}
}
&>
&> [200,300,40000].map(bfs);
[ 20, 24, 283 ]
看完高票答案後感覺思路確實好,補代碼.
function calc(x){
if (x&<0) x=-x;
let n1=parseInt((1+Math.sqrt(8*x+1))/2,10);
let x1=n1*(n1-1)/2
if (x1==x) return n1-1;
let x2=x1+n1-x;
if (!(x21)) return n1;
if (!(n11)) return n1+1;
return n1+2;
}
for(i=0;i&<1000;i++){
if (bfs(i)!=calc(i)) console.log(i)
}
聲明:僅考慮正距離。
首先,反過來考慮一個問題:
使用跳躍x次能走過的哪些距離?答案是:對於任意的,只要k與x奇偶性相同,都可以到達。首先是跳躍x次能夠到達的最遠距離。那麼對於,僅需要在第一步時回跳即可,即對於,都是可以找到組合實現回跳的。(總能找到{1,...,x}的子集表示任意小於S的數字。)基於以上結論,對於所需達到的距離k,我們只需要找到最小的x即可。1:利用二次方程求解公式求出x0double x0=Math.ceil((Math.sqrt(1+8*k)-1)/2);
2:奇偶性判斷如果k和奇偶性不同,則需要修正x0
if(k % 2 == 0){
if(x0 % 4 == 1){
x0 += 2;
} else if (x0 % 4 == 2){
x0 += 1;
}
}else{
if(x0 % 4 == 0){
x0 += 1;
} else if (x0 % 4 =3){
x0 += 2;
}
}
一開始覺得很難,覺得自己很水。。。。後來洗澡的時候想了一下,居然想出來答案了,真是覺得自己萌萌噠。
答案樓上已經說得很清楚了,我簡單地說說:
1.螞蟻最少跳多少步?
答:螞蟻一直往前跳,直到跳過「輸入數據」位置(跳了p步)。螞蟻的最短步數為p或者p+1。2. 有沒有比p少的步數?
答:螞蟻一直往前跳都跳不到「輸入數據」,比p少絕壁不可能。3. 為什麼第p步一定能剛剛好跳到「輸入數據」?
答:螞蟻一直往前跳p步,跳到M處。假設螞蟻第1步往後跳,其他都往前跳,那麼就能跳到M-2*1處。假設螞蟻第2步往後跳,其他都往前跳,那麼就能跳到M-2*2處。假設螞蟻第1和2步往後跳,其他都往前跳,那麼就能跳到M-2*(1+2)處。所以理論上螞蟻能跳到任何一個「輸入數據」的地方,只要控制好向後步數x,就能得到M-2*x=任何數(與M相差2,4,6,8等等任何偶數的數)。如果「輸入數據」與M相差是奇數,則再往前跳一次,重複上面的過程。也就是p+1步。我小學的時候,去參加南師附中江寧分校的小升初3+3班的考試,數學卷就有這道題(;一_一)
可以這樣想,如果沒有後跳的話,跳躍過程是一個1~n的求和過程,即
現在過程中加入了後跳,所以上面的求和式中有某些元素會變成負,由正變負相當於減2k,因此上式可改為, 即1~n的和減去一個偶數後等於x
所以這個問題會有兩種情況:
1. 2.換句話說,不斷的求1~n的和,然後第一個滿足上面兩種情況之一的就是所需的解,代碼的話這樣應該就可以了,注意x可以為負,不過負數只表示方向變化,並不影響思路class Solution:
def JumpSteps(self, x):
s = 0
i = 0
steps = 0
stop = False
if x &< 0:
x = -x
if x == 0 or x == 1:
return x
while not stop:
i += 1
s += i
steps += 1
# print s, " ", steps
if (s - x) &>= 0 and (s - x) % 2 == 0:
stop = True
return steps
大號被禁言了換小號來重新答一發
int jumpTo(long x) {
if (x &< 0) x = -x;long sum = 0; int n = 1; for(; sum &< x; n++) sum += n;//這裡執行完了以後sum = n(n - 1)/2//並且滿足條件sum &>= x//sum和x奇偶性相同,這裡很多答主都指出了,雖然我大號答的時候並沒有多少人指出來
if ((sum - x) 1 == 0) return n - 1;//奇偶性不同的話,就要看下一個,那麼要找一個奇數n才可以,這裡還是有人以為return n就可以了,拿衣服
return n | 1;}我這個本來是第四個答案吶…………好桑心第一印象:如果x大於0,可以至多2x步解決問題,先向後跳再向前跳,會前進1個單位,重複x次可以到達x處。
--------------------------------------------------------如果採用計算機變成可以這樣轉換問題:一個從1開始的連續數字組成的累加算式,每個數字的符號待定(正號或者符號),等式右邊是目標坐標的值。如果等式成立,那麼答案找到。正號代表朝著x的方向,符號表示反向。編程實現步驟如下:
1. 連續數字為從1到x(x跳最遠能夠等於或超過目標坐標,但x-1跳不能達到目標坐標)2. 遍歷所有數字元號的組合。等式成立則結束,返回答案;否則下一步3. 連續數字增加1個。如果連續數字超過2x則結束,沒有找到答案;否則回到第一步根據之前的分析,不可能沒有答案,最多2x步。--------------------------------------------------------看來難點在於如何用最少的步數達到目的,以及如何最快找到最小的步數。根據數學推導不難驗證以下結論:
x步最遠可以走到S(x),註:S(x)=(x^2+x)/2,當目標處於這些點上時可以不用浪費跳步。其餘的點必須有不同方向的跳步組成。x步中如果只有一步走反向,那麼可以到達的點為S(x)-2k,k代表反向的距離,值為從1到x中任意一個。點的範圍是S(x-2)-1到S(x-2)-2。如果增加兩步,可以走到S(x)+1或者S(x)-1。走法分別是-(x+1)+(x+2),+(x+1)-(x+2)。x步最多增加兩步,就可以覆蓋所有從S(x-1)到S(x)上的點。因此之前的程序可以簡化了,直接計算得出結論。
步驟如下:1. 計算出x(x跳最遠能夠等於或超過目標坐標,但x-1跳不能達到目標坐標)2. 如果目標和(x^2+x)之差為偶數或者0,可以直接得出反方向的那一步,其餘都為正向;3. 如果目標和(x^2+x)之差為奇數,先計算差減一的反方向的那一步,然後-(x+1)+(x+2)調整。這個方法很快,但有可能不是最優,有目標可能不需要多兩步。但是可以接受了。
--------------------------------------------------------如果你要求極致,好吧讓我們繼續做推導根據數學推導不難驗證以下結論:
如果x是偶數,那麼x+1步中只有一步反向所覆蓋的點中會覆蓋S(x-1)到S(x)之間所有S(x)-2k+1的點。因此可以優化上一次的程序第3步如下:
3. 如果目標和(x^2+x)之差為奇數且x是偶數,步數加1,計算得出反方向的那一步,其餘都為正向;4. 如果目標和(x^2+x)之差為奇數且x是奇數,先計算差減一的反方向的那一步,然後-(x+1)+(x+2)調整。至此,找到最優解:)--------------------------------------------------------還沒有結束,能找到所有的最優解嗎?答案當然是能,但是怎麼樣最快呢?歡迎大家繼續討論。問題可以簡化為,求的值
因為每次只能向前或者向後跳個單位,所以我們只能先找到後面可以取到的最大值,即然後通過改變數字前面的正負號使為要求的數值,可以概述為向後求最大然後向前取整,但向前取的時候只能使值為偶數(因為把一個值由正改為負時相當於減去2倍的這個值),所以減的值只能是偶數
由上可知:依次向後找值為時的最大和,使其與所求值的差為偶數即可:,為題目所給的值,為所求的步數#include &
using namespace std;
int main()
{
int k;
int sum,n,s;
while(cin&>&>k,k)
{
sum=1;
n=1;
while(sum&
{
if(sum&>n)
{
ss[n-1]=true;
}else
{
ss[sum-1]=true;
break;
}
sum-=n;
}
for(int i=0;i&
剛上大一,,,剛學計算機,,,請各位大神幫忙看看可行否,,,算了幾個簡單的值,都是對的。。。
bfs可以沒啥說的
但我覺得 dp也可以跳了i步了,當前位置是j,下次前跳為1,後為0dp[i+1][j+i+1][0] = dp[i][j][1];dp[i+1][j+i+1][1] = dp[i][j][1];dp[i+1][j-i-1][0] = dp[i][j][0];dp[i+1][j-i-1][1] = dp[i][j][0];送分題 1 +/- 2 +/- 3 …
由於局部最小解(n)是 1-2+3 …=n(每次遞增1)所以全局最優解小於等於局部最小解2n全局可能最優解(m) 1+2+3...n=m是符合全為+或- 所以全局最優解大於等於這個m = (n+n^2)/2
n&>= x &>= m
證出n&>3時有一般解
(y1,y2)=(x+1-n+n1)/2
n1為小於n的最大的m
y為設為-的數 可能是1個也可能是2個取決於右邊的奇偶性O(1)複雜度
偽dp問題bfs簡單粗暴
只考慮位置的絕對值。先求始終向正向到達或超過所需步數n。如果此時離目標距離為偶數,則n為所求。否則如果n為偶數,則n+1為所求。否則n+2為所求。
寬度遍歷嘛?
推薦閱讀:
※如果讓你清洗西雅圖市所有的窗戶,你索價多少?
※從HR的角度看,面試有哪些注意事項?
※如何成為一名好的面試官?
TAG:演算法 | 面試問題 | 樂視網信息技術北京股份有限公司 | 面試難題 |