移动窗口RMQ性能改进

时间:2017-02-09 14:04:40

标签: c++ algorithm rmq

假设我有一个长度为A的整数数组N,我也有一个整数L< = N

我想找的是范围[0,L-1],[1,L],[2,L + 1] ...... [NL,N-1]

(如从左到右的长度为L的移动窗口)

我的算法现在是O(N lg N),其中O(N lg N)预处理:

  1. 将所有数字A[0...L-1]保存在多集S中,并按顺序将该数字存储在队列Q中。 [0,L-1]的最小值只是S的第一个元素。 O(N lg N)
  2. 弹出Q的第一个元素,在S中找到此元素并将其删除。然后在A[L]中推送S。 [1,L]的最小值只是S的第一个元素。 O(lg N)
  3. 对所有可能的范围重复步骤2,每次迭代移至下一个元素。 O(N)
  4. 总计为O(N lg N)。

    我想知道是否有任何算法可以达到以下要求:

    1. 预处理时间(如果需要)是O(N)
    2. 如果O(1)
    3. ,则查询时间

      我对RMQ做了一些研究,我发现最近的方法是使用稀疏表来实现O(1)查询时间但是O(N lg N)预处理时间。 reduce RMQ to LCA问题可以满足要求但需要对数组A进行一些限制的另一种方法。

      那么,在A没有限制的情况下,解决我的问题时可以满足要求吗?

1 个答案:

答案 0 :(得分:2)

是的,请使用deque。我们将保持元素按升序排序,因此对于当前位置[i - L + 1, i],第一个元素始终是i中的最小元素。我们不会保留实际元素,但他们的位置。

d = empty deque
for i = 0 to n-1:

    // get rid of too old elements
    while !d.empty && i - d.front + 1 > L:
        d.pop_front()

    // keep the deque sorted
    while !d.empty && A[d.back] > A[i]        
        d.pop_back()

    d.push_back(i)
    // A[d.front] is the minimum in `[i - L + 1, i]

由于每个元素最多进入和离开一次双端队列,因此O(n)// // ViewController.swift // MobileAppDemo // // Created by Mikko Hilpinen on 27.10.2016. // Copyright © 2016 Mikkomario. All rights reserved. // import UIKit import FBSDKCoreKit import FBSDKLoginKit import Firebase import FirebaseAuth import SwiftKeychainWrapper fileprivate struct RegisterInfo { let email: String let password: String } class SignInVC: UIViewController { @IBOutlet weak var emailField: UITextField! @IBOutlet weak var passwordField: UITextField! override func viewDidLoad() { super.viewDidLoad() } override func viewDidAppear(_ animated: Bool) { if User.currentUserId != nil { print("AUTH: USING EXISTING KEYCHAIN") User.startTrackingCurrentUser() //performSegue(withIdentifier: "ToFeed", sender: nil) } else { print("AUTH: NO EXSTING KEYCHAIN") } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { print("AUTH: Preparing for segue \(segue.identifier)") if let registrationVC = segue.destination as? RegisterVC { print("AUTH: Found registration VC") if let info = sender as? RegisterInfo { print("AUTH: Sending email (\(info.email)) and password (\(info.password.characters.count) chars) information: ") registrationVC.setBaseInfo(email: info.email, password: info.password) } } } @IBAction func signInButtonPressed(_ sender: UIButton) { if let email = emailField.text, let password = passwordField.text { FIRAuth.auth()?.signIn(withEmail: email, password: password) { (user, error) in if let error = error { // TODO: Handle other errors here as well switch FIRAuthErrorCode(rawValue: error._code)! { case .errorCodeUserNotFound: print("AUTH: USER NOT FOUND -> CREATING NEW USER") print("AUTH: Sending email \(email) and password \(password.characters.count) characters") self.performSegue(withIdentifier: "RegisterUser", sender: RegisterInfo(email: email, password: password)) default: print("AUTH: ERROR IN EMAIL LOGIN \(error)") // TODO: Inform user } } else { print("AUTH: EMAIL AUTH SUCCESSFUL") User.currentUserId = user?.uid User.startTrackingCurrentUser() self.performSegue(withIdentifier: "ToFeed", sender: nil) } } } // TODO: Inform user that the field contents are missing } fileprivate func firebaseAuth(with credential: FIRAuthCredential) { if FIRAuth.auth() == nil { print("AUTH: NO AUTH SERVICE AVAILABLE") } FIRAuth.auth()?.signIn(with: credential) { (user, error) in if let error = error { print("AUTH: UNABLE TO AUTHENTICATE TO FIREBASE") print("AUTH: \(error)") } else { if let user = user { print("AUTH: SUCCESSFULLY AUTHENTICATED WITH FIREBASE") // Updates current user data var userName = "User" var image: UIImage? if let retrievedName = user.displayName { userName = retrievedName } if let retrievedImageUrl = user.photoURL { if let data = try? Data(contentsOf: retrievedImageUrl) { image = UIImage(data: data) } } User.post(uid: user.uid, provider: user.providerID, userName: userName, image: image) { user in User.currentUser = user User.startTrackingCurrentUser() self.performSegue(withIdentifier: "ToFeed", sender: nil) } } } } } }