和小于k的最長連續(xù)子串

問題

已知一個長度為n的數(shù)組(允許負數(shù)), 和一個整數(shù)k, 求:和小于k的最長連續(xù)子串?

例如:

k=184, A=[431, -15, 639, 342, -14, 565, -924, 635, 167, -70],

和小于184的最長子串為A[3..6]

寫個簡單測試先

require_relative '../longest_subarray_with_sum_less_than_k'

describe LongestSub do
  let(:array) {[431, -15, 639, 342, -14, 565, -924, 635, 167, -70]}
  let(:bound) {184}
  let(:result) {subject.longest(array,bound)}
  let(:ans) {array[3..6]}
  it "should compute the longest subarray whose sum <= bound" do
    expect(result).to eq ans
  end
end

分析

如果暴力枚舉起點和終點,復(fù)雜度為O(n^2)。能不能找到一些規(guī)律優(yōu)化呢?

Make hands dirty

單純考慮原數(shù)組好像找不到規(guī)律。

考慮前綴和,此時問題轉(zhuǎn)換為已知pre數(shù)組,求pre[j]-pre[i]<=k的距離最大(i,j)對.

由于有負數(shù),pre數(shù)組沒有遞增規(guī)律。

第一個元素的右端點,就已經(jīng)難以確定了,必須從右到左掃描,直到差值<=k,有可能一個都不成功;而且,算好i后,算i+1時好像還是要掃描所有之后的右端點。

于是考慮對pre排序, 然后可以用“雙指針”,不斷移動右指針直到>k,并一直保存當前最右下標。這樣需要復(fù)雜度O(nlogn)排序+O(n) == O(nlogn)

Make it better

還有更好的方法嗎?有沒有什么規(guī)律,來排除一些值呢?

可以發(fā)現(xiàn)右端點中,如果j1<j2而且pre[j1]>=pre[j2],那肯定不會選j1, 因為j2既比j1遠,求和時結(jié)果又比j1小。所以,可以從右到左掃描一遍,過濾掉不可能的右端點。

而且發(fā)現(xiàn),這樣過濾后的右端點在pre上是遞增的,就可以用“雙指針”求了。

復(fù)雜度 = O(n)過濾 + O(n)掃描 = O(n)

代碼:

class LongestSub
  def longest(arr,bound)
    reset(arr,bound)
    l,r = [(0...size),poss_r].map(&:to_enum)
    loop { update(l,r) }
    arr[@longest_range]
  end

  def update(l, r)
    i,j = [l,r].map(&:peek)
    if i<=j && presum(j,i)<=bound
      @longest_range = [@longest_range, (i..j)].max_by(&:size)
      r.next
    else
      l.next
    end
  end

private
  attr_reader :arr, :bound
  def reset(arr,bound)
    @arr,@bound=[arr,bound]
    @poss_r = @pre  = nil
    @longest_range = (0...0)
  end
  def size; arr.size end
  def pre
    @pre ||= arr.reduce([0]){|res,v| res << res.last+v}
  end
  def presum(j,i=0)
    pre[j+1] - pre[i]
  end
  def poss_r
    @poss_r ||= (0...size).reverse_each.reduce([]) do |res,i|
      res.unshift(i) unless res.first && presum(i) >= presum(res.first)
      res
    end
  end
end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容