貝殼網2020筆試題解析

  2019年8月10號我參加貝殼筆試,沒想到是四道編程題,這個着實讓我措手不及。下面我就來帶你們看看這四道題目。首先我要吐槽下賽碼網的系統,爲啥非得寫輸入輸出,能不能學學Leetcode !html

 第一題:計算絕對值

  題目描述:給出n個整數,要找出相鄰兩個數字中差的絕對值最小的一對數字,若是差的絕對值相同的,則輸出最前面的一對數。2<=n<=10,正整數都在10^16次方範圍內。算法


  輸入:輸入包含兩行,第一行是n,第二行是n個用空格間隔的正整數。編程

  輸出:輸出包含一行兩個正整數,要求按照原來的順序輸出。數組

  樣例輸入:9服務器

       1 3 4 7 2 6 5 12 32app

  樣例輸出:3 4測試

  這道題應該是四道題中最簡單的一道,有不少種方法。其中要注意的是對於差值相同的多對數,只輸出最前面的一對數。在筆試時我用的map結構實現去重,實際上是把這道題作複雜了,簡單的一個數組就OK了。優化

  下面來看看第一種作法,比較簡單,你們就直接看代碼吧。第一種解法的平均時間複雜度爲O(n+m), 空間複雜度爲O(m)。spa

  第二種解法利用map去存儲差值和數字對,時間複雜度和空間複雜度和第一種方法相同。.net

package main

import (
    "fmt"
    "math"
)

func solution(nums []int) []int {
    minuss := make([]float64, len(nums))
    for i := 0; i < len(nums)-1; i++ {
        minuss[i] = math.Abs(float64(nums[i] - nums[i+1]))
    }

    min := math.MaxFloat64
    mini := 0
    for i, e := range minuss {
        if e < min {
            min = e
            mini = i
        }
    }
    res := []int{nums[mini], nums[mini+1]}
    return res
}

func solution1(nums []int) []int {
    m := make(map[int][]int)
    for i := 0; i < len(nums)-1; i++ {
        minus := int(math.Abs(float64(nums[i] - nums[i+1])))
        pair := []int{nums[i], nums[i+1]}
        if _, ok := m[minus]; !ok {
            m[minus] = pair
        }
    }
    minK := int(math.MaxInt64)
    for k, _ := range m {
        if k < minK {
            minK = k
        }
    }
    return m[minK]
}

func main() {
    var n int
    var nums []int
    fmt.Scanf("%d", &n)
    for i := 0; i < n; i++ {
        var tmp int
        fmt.Scanf("%d", &tmp)
        nums = append(nums, tmp)
    }
    res := solution1(nums)
    for _, elm := range res {
        fmt.Print(elm, " ")
    }
}

 第二題:月光寶盒

  題目描述:小希偶然獲得了傳說中的月光寶盒,然而打開月光寶盒須要一串密碼,雖然小希並不知道具體的密碼是什麼,可是月光寶盒的說明書上有着一個長度爲n(2<=n<=50000)的序列a(10^-9 <= a <= 10^9)。上面寫着一句話:密碼是這個序列的最長嚴格上升子序列的長度(嚴格上升子序列是指子序列的元素是嚴格遞增的),請你幫小希找出這個密碼。

  輸入:

  第一行,1個數n。n爲序列長度(2<=n<=50000)

  第2到n+1行,每行一個數,對應序列的元素

  輸出:

  正整數,表示嚴格上升子序列的長度

  樣例輸入:

  8

  5

  1

  6

  8

  2

  4

  5

  10

  樣例輸出:

  5,由於目標子序列爲1 2 4 5 10

  這道題在Leetcode上有原題,方法也不少,我在這裏講兩種方法,動態規劃和二分加貪心法。

  方法1:動態規劃法

  動態規劃兩要素:遞推方程和初始條件,咱們令遞推方程F(i)表示以nums[i]爲最大值的前i-1個元素的最長上升子序列(nums[0 ... i-1])的長度。咱們令遞推方程 F(i) = max( max( F(0), F(1), ... , F(i-1) )+1, F(i)), 初始時F中的全部元素都等於0。能夠看出整個遞推方程其實是求兩個最大值的過程。代碼以下所示:

  

func max(a, b int) int {
    if a > b {
        return a
    } else {
        return b
    }
    return a
}

func lengthOfLIS(nums []int) int {
    F := make([]int, len(nums))
    var maxL int
    for i := 0; i < len(nums); i++ {
     //內層循環找nums[i]以前的最長上升子序列長度,只在nums[i] > nums[j]進行計算
for j := 0; j < i; j++ { if nums[i] > nums[j] { F[i] = max(F[j]+1, F[i]) } }
     //外層循環求整個F[i]的最大值 maxL
= max(maxL, F[i]+1) } return maxL //return maxf }

  方法2:二分加貪心算法

  咱們用 tail[i] 表示長度爲 i+1  的子序列的最小的元素。好比對於序列[4,5,6,3],tail數組的填充過程以下所示。

  len = 1 : [4], [5], [6], [3] => tails[0] = 3

  len = 2 : [4, 5], [5, 6] => tails[1] = 5

  len = 3 : [4, 5, 6] => tails[2] = 6

  求解的過程就是不斷向tail中加入合適的元素的過程,咱們遍歷全部長度的子序列並找到一個序列結尾最小的元素加入到tail中。爲何要找結尾最小的元素呢?

 由於對於一個上升序列,當前的元素越小越有利於後續的元素的加入。這就是貪心的所在。每次循環咱們只作兩件事:

  1. 若是nums[i]比當前的全部tail[i]元素都大,直接將其增長到尾部。

  2.  若是nums[i]比tails[i]小那麼更新tails[i]。

  

/*func lengthOfLIS(nums []int) int {
    tails := make([]int, len(nums))
    pos := 0
    for i := 0; i < len(nums); i++ {
        low, high := 0, pos
        for(low != high) {
            mid := (low + high)/2
            if tails[mid] < nums[i] {
                low = mid + 1
            } else {
                high = mid
            }
        } 
        tails[low] = nums[i]
        if low == pos {
            pos++
        }
    }
    return pos
}*/

 

第三題:舉重大賽

  題目描述:舉重大賽開始了,爲了保證公平,要求比賽雙發體重較小值要大於等於較大值的90%。那麼對於N我的最多能進行多少場比賽呢。任意兩人只能進行一場比賽。

  輸入:

  第一行N,表示參賽人數

  第二行N個正整數,表示體重。

  輸出:

  一個數,表示最多進行的比賽次數。

  這道題,最簡單的想法就是遍歷每個組合而後判斷整個組合是否知足條件。可是暴力法雖然簡單,可是卻沒有超時了。因此仍是不行。其實暴力法是存在大量重複計算的,所以有很大的

  優化的空間。好比若是 a >= b * 0.9, 那麼任何大於a的元素和b均可以進行比賽。

  

package main

import (
    "fmt"
    "sort"
)

func satisfy(a, b int) bool {
    if float64(a) >= float64(b)*0.9 {
        return true
    }
    return false
}

func solution(nums []int) int {
    sort.Ints(nums)
    count := 0
    for i := 0; i < len(nums); i++ {
        for j := i + 1; j < len(nums); j++ {
            if satisfy(nums[i], nums[j]) {
                count += len(nums) - j
                break
            }
        }
    }
    return count
}

func main() {
    var n int
    var nums []int
    fmt.Scanf("%d", &n)
    for i := 0; i < n; i++ {
        var tmp int
        fmt.Scanf("%d", &tmp)
        nums = append(nums, tmp)
    }
    res := solution(nums)
    fmt.Println(res)
}

 

第四題:特殊的測試

  題目描述:小C在作一種特殊的服務器負載測試,對於一個請求隊列中的請求,每一個請求都有一個負荷值。爲了保證服務器穩定,請求隊列中的請求負荷必須按照先增後減,或者遞增或者遞減的規律。好比

  [1,2,8,4,3],[1,3,5],[10]是符合規律的。還有一些不知足的,好比[1,2,2,1],[2,1,2],[10,10]。如今給你一個請求隊列,你能夠對請求的負荷值進行增長,要求你調整隊列中請求的

  負荷值,最後輸出使得隊列知足條件的最小增長總和。

  輸入:輸入兩行,第一行N表示請求的個數,第二行表示每一個請求的符合值。

  輸出:輸出這個最小增長總和

  樣例輸入:

  5

     1 4  3 2 5

  樣例輸出:

      6 (此時合法隊列是1 4 5 6 5),最小增長總和=2+4 = 6  

  

package main

import (
    "fmt"
)

func solution(nums []int) int {
    n := len(nums)
    if n == 1 {
        return 0
    }

    if n == 2 && nums[0] == nums[1] {
        return 1
    }

    if n == 2 && nums[0] != nums[1] {
        return 0
    }

    cp := make([]int, n)
    copy(cp, nums)

    var i, j int
    for i = 0; i < n-1 && nums[i] < nums[i+1]; i++ {
    }

    for j = n - 1; j > 0 && nums[j] < nums[j-1]; j-- {
    }

    for i < j {
        if nums[i] < nums[j] {
            if (nums[i+1] - nums[i]) < 1 {
                nums[i+1] = nums[i] + 1
            }
            i++
        } else {
            if (nums[j-1] - nums[j]) < 1 {
                nums[j-1] = nums[j] + 1
            }
            j--
        }
    }
    return sum(nums) - sum(cp)
}

func sum(nums []int) int {
    s := 0
    for _, elm := range nums {
        s += elm
    }
    return s
}
func main() {
    var n int
    var nums []int
    fmt.Scanf("%d", &n)
    for i := 0; i < n; i++ {
        var tmp int
        fmt.Scanf("%d", &tmp)
        nums = append(nums, tmp)
    }
    res := solution(nums)
    fmt.Println(res)
}

 

參考:

   https://leetcode.com/problems/longest-increasing-subsequence/discuss/74824/JavaPython-Binary-search-O(nlogn)-time-with-explanation

   https://blog.csdn.net/wbin233/article/details/77570070

   https://www.cnblogs.com/haimishasha/p/11333201.html

相關文章
相關標籤/搜索