《劍指Offer》- 連續子陣列的最大和或最小和

胡哥有話說發表於2020-04-29

前言

本文是《劍指Offer》系列(JavaScript版)的第一篇,題目是“連續子陣列的最大和或最小和”。

話不多說,開始“打怪”修煉...

一、理解題目

以“連續子陣列的最大和”為例,相當於我們在陣列中,計算連續的子陣列的和,找尋最大值。如在陣列[3, -2, 1, 2, 4, -6, 5]中連續子陣列的最大和為:3 + (-2) + 1 + 2 + 4 = 8

輸入:[3, -2, 1, 2, 4, -6, 5]
輸出:8

一定要準確的理解題意,如不是特別明確,建議與面試官再次溝通確認,避免需求與實現不一致的情況。

二、解決方案

連續子陣列的最大和

這道面試題有幾種解決方案呢?可能在很多個同學的腦海裡會出現這樣的一種方案:

1. 求連續子陣列組合方案:

將陣列中的元素進行連續子陣列的組合,每一種組合計算出一個值,依次比較後取出最大值。那這種方式是可以肯定是可以最終的效果的,But這麼處理的話,會有多少種組合方案呢?

以陣列 [1, -1, 2, -3, 5]為例:
	連續子陣列有:N + (N-1) + (N-2)...  +  1 = n*(n+1) / 2

隨著陣列長度N的值越大,組合數量肯定是越大!同時在獲取階乘後,還需要再次進行一次最大值得比較。

劃重點:

此方案雖可以實現最終的效果,但是確實十分不可取的!

2. 最優解方案

在面試時面試題除了固定的套路和演算法外,要多嘗試邏輯思維的轉變...

技術方案:
	1. 初始化兩個變數:sum(連續子陣列的累加和)、max(最大值)
	2. 遍歷陣列元素,考慮sum的情況: 
		sum >= 0,將當前元素的值進行累加
		sum < 0,注意,sum的值為負值,不管當前的元素值是什麼,累加sum(負數)肯定值最終會變小的,所以此刻,要重新對sum進行賦值操作
	3. 每次遍歷時,都要比較sum和max的大小, 如果 sum > max,進行賦值max = sum
	4. 返回最終的結果max

接下來,我們來看下程式碼的實現:

/**
 * getGreatestSumOfSubArray()
 * @description 獲取連續子陣列中最大和
 * @param Array arr 指定的陣列
 * @returns Number sum 最大和
*/
function getGreatestSumOfSubArray (arr) {
  // 容錯邊界處理
  if (!Array.isArray(arr) || arr.length === 0) {
    return 0
  }

  // 解構,初始獲取陣列的第一個元素值
  // 注意:一定不能把sum和max設定初始化為0,必須要考慮陣列元素中全部為負數的情況
  let [ sum ] = arr
  let [ max ] = arr
  
  let len = arr.length
  for (let i = 1; i < len; i++) {
    // 如果當前sum累加 < 0,重新初始化當前元素值;否則執行累加
    if (sum < 0) {
      sum = arr[i]
    } else {
      sum += arr[i]
    }

    // 比較累加和與最大值
    if (sum > max) {
      max = sum
    }
  }
  
  return max
}

// 呼叫
let max = getGreatestSumOfSubArray([3, -2, 1, 2, 4, -6, 5])
console.log(max) // 8

OK,這樣我們就實現了需求,小朋友,你還有問號嗎?

連續子陣列的最小和

“連續子陣列的最小和” 這個需求的實現原理和“連續子陣列的最大和”的實現基本是一致的,唯一的區別點為:當sum的值 > 0為正數時,累加就無意義了,需要重新賦值為當前值。我們來看下程式碼的實現

/**
 * getLeastSumOfSubArray()
 * @description 獲取連續子陣列的最小和
 * @param Array arr 指定的陣列
 * @returns Number min 最小和
*/
function getLeastSumOfSubArray (arr) {
  if (!Array.isArray(arr) || arr.length === 0) {
    return 0
  }

  // 初始化
  let [ sum ] = arr
  let [ min ] = arr

  // 遍歷陣列元素,如果sum是一個正數,累加就無意義,重新賦值為當前項;
  let len = arr.length
  for (let i = 1; i < len; i++) {
    if (sum > 0) {
      sum = arr[i]
    } else {
      sum += arr[i]
    }
    if (sum < min) {
      min = sum
    }
  }

  return min
}

let min = getLeastSumOfSubArray([-1, -2, 3, 2, -4, -8])
console.log(min) // -12 = (-4) + (-8)

這個瞭解了不...

後記

以上就是胡哥今天給大家分享的內容,喜歡的小夥伴記得點贊收藏呦,關注胡哥有話說,學習前端不迷路,歡迎多多留言交流...

胡哥有話說,一個有技術,有情懷的胡哥!現任京東前端攻城獅一枚。

胡哥有話說,專注於大前端技術領域,分享前端系統架構,框架實現原理,最新最高效的技術實踐!

相關文章