加油站問題

問題描述

有一個環形軌道,上有若干加油站,一輛小車(初始時油箱爲空,油箱容量無線)從某個加油站出發繞一圈,路上需要耗油,已知 加油站的總油量和路上需要消耗地油量一樣多,問是否可以找到從一個加油站出發,小車可以正常繞一圈?

問題解析

其實上面的題與下面的題目類似:

有一個循環數組,{1, 2, -3, 4, -5, -8, 9},問找出一個數,使得從該數出發,往右的所有子數組,比如 {2}, {2,-3}, {2, -3, 4}, {2, -3, 4, -5}, {2, -3, 4, -5, -8}, {2, -3, 4, -5, -8, 9}, {2, -3, 4, -5, -8, 9, 1} 每個子數組的和,都要 >= 0,即不爲負。顯然以2開始,是不行的,因爲 {2, -3} 的和就是-1,已經不滿足條件了。

問題解決1

構造如下一個雙向鏈表,鏈表節點中第一個元素指示爲index,第二個元素爲對應的值:
{0,1} <-> {1, 2} <-> {2, -3} <-> {3, 4} <-> {4, -5} <-> {5, -8} <-> {6, 9}

順序掃描,從頭開始。找出第一個節點,其值小於0,。
找出的節點爲 {2, -3},那麼 * 我們要找的答案必須不是以該元素開始的,因爲它已經是-3了*,那麼將 {2, -3} 和前一項 ({1, 2})整合,新的節點爲 {1, -3+2} 即 {1, -1}。整合後的節點的index值取整合前的前一項({1,2})的index值。
{0,1} <-> {1, -1} <-> {3, 4} <-> {4, -5} <-> {5, -8} <-> {6, 9}
現在發現 {1, -1} 還是-1,那麼繼續往前整合:
{0,0} <-> {3, 4} <-> {4, -5} <-> {5, -8} <-> {6, 9}

ok,現在可以開始考慮 {3,4}, 沒問題,繼續往下掃描。 遇到 {4, -5}節點時,又是-5,因此繼續往前整合:
{0,0} <-> {3, -1} <-> {5, -8} <-> {6, 9}
{0,-1} <-> {5, -8} <-> {6, 9}
{5, -8} <-> {6, 8} // 將 {0,-1} 與循環數組的前一項({6,9})整合

此時剩下 {5, -8},繼續整合:
{6, 0}

剩下index就是6,因此對應的那個值即 9,就是我們需要的答案。
每個節點最多被掃描一次和刪除一次。時間複雜度爲 O(n),空間複雜度爲 O(n)。

問題解決2

上述方案中,空間複雜度還是有點高。因此需要更好的方法。
其實在上述方案中,隱藏着另一幅視角:

倘若 arr[0..k]爲 arr[0..0] ~ arr[0..n-1] 之間的和首次爲負數,那麼 arr[0..k] 可以整合爲一個負數來看待。因此此時 arr[k] 必定是一個必經大的負數,那麼該負數可以一直往前整合,直到把 arr[0]也整合進來。整合之後的值依然爲負數。

OK,在上述情況下繼續討論,此時可以繼續直接從 arr[k+1]往下掃描。直到 arr[k+1 .. j] 爲負數,此時這個區間的數可以整合成一個負數。

直到從 arr[i .. n-1] 這段區間爲正數,而且該正數可以恰好cover掉之前整合後的若干負數。那麼 i 就是我們所求的。 從 i 開始的n的長度遞增的子數組,其和均爲非負。

算法思想:

 sum <- 0
for each i in 0 .. n-1
    sum <- sum + arr[i]
    if sum < 0 then 
        sum <- 0
    else if i == n-1 then 
        return i    // 一定會有個i,是的該式子滿足 且此時 sum > 0
    i <- i+1

時間複雜度爲O(n),空間複雜度爲O(1)

發佈了118 篇原創文章 · 獲贊 17 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章