232. 用栈实现队列 (Implement Queue using Stacks)

用栈实现队列 (Implement Queue using Stacks)

题目描述

使用两个栈实现一个队列。队列的操作包括 push(x)pop()peek()empty()

示例:

plaintext 复制代码
MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

注意:

  • 你只能使用标准的栈操作,即 push to toppeek/pop from topsizeis empty 这些操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
  • 假设所有操作都是有效的。例如,当队列为空时,不调用 poppeek 操作。

代码实现

swift 复制代码
class MyQueue {

    private var stack1: [Int]
    private var stack2: [Int]

    /** Initialize your data structure here. */
    init() {
        stack1 = [Int]()
        stack2 = [Int]()
    }
    
    /** Push element x to the back of queue. */
    func push(_ x: Int) {
        stack1.append(x)
    }
    
    /** Removes the element from in front of queue and returns that element. */
    func pop() -> Int {
        if stack2.isEmpty {
            while !stack1.isEmpty {
                stack2.append(stack1.removeLast())
            }
        }
        return stack2.removeLast()
    }
    
    /** Get the front element. */
    func peek() -> Int {
        if stack2.isEmpty {
            while !stack1.isEmpty {
                stack2.append(stack1.removeLast())
            }
        }
        return stack2.last!
    }
    
    /** Returns whether the queue is empty. */
    func empty() -> Bool {
        return stack1.isEmpty && stack2.isEmpty
    }
}

注意点

在 Swift 中,Array 的实例(或对象)方法 removeFirst()removeLast() 除了执行本身的 remove 操作,还会 return 对应 removed 元素。

swift 复制代码
// Removes and returns the first element of the collection.
@discardableResult
@inlinable public mutating func removeFirst() -> Element
// Removes and returns the last element of the collection.
@discardableResult
@inlinable public mutating func removeLast() -> Element

swift 复制代码
// Error: Cannot use mutating member on immutable value of type '[Int]'
[1,2,3].removeFirst()

在 Swift 中,如果你试图在不可变数组上调用可变方法(例如 removeFirst()),会导致错误。为了修复这个错误,你需要确保数组是可变的。下面是一些正确处理的方式:

使用可变数组

确保你的数组是用 var 声明的,这样你就可以对它进行修改。

swift 复制代码
var array = [1, 2, 3]
array.removeFirst()  // 现在不会报错
print(array)  // 输出: [2, 3]

使用不可变数组并创建可变副本

如果你的数组必须是不可变的,你可以创建一个可变副本来进行修改。

swift 复制代码
let immutableArray = [1, 2, 3]
var mutableArray = immutableArray
mutableArray.removeFirst()
print(mutableArray)  // 输出: [2, 3]

完整示例

以下是如何在实际代码中使用可变数组的示例:

swift 复制代码
func processArray() {
    var array = [1, 2, 3]
    array.removeFirst()
    print(array)  // 输出: [2, 3]
}

processArray()

通过确保数组是可变的,你可以成功调用诸如 removeFirst() 之类的可变方法,而不会遇到错误。


拓展 - Swift 中为什么没有原生支持的 Stack 和 Queue 数据结构 ?

Swift 中没有原生支持的 Stack 和 Queue 数据结构的原因主要有以下几个方面:

1. 泛用数据结构的灵活性

Swift 标准库提供了一些强大的泛用数据结构,例如 ArrayDictionary,它们可以用来构建多种不同的数据结构。Array 本身就可以方便地用来实现 Stack 和 Queue,只需要添加一些扩展方法。例如:

swift 复制代码
// 实现 Stack
struct Stack<T> {
    private var elements: [T] = []

    mutating func push(_ element: T) {
        elements.append(element)
    }

    mutating func pop() -> T? {
        return elements.popLast()
    }

    func peek() -> T? {
        return elements.last
    }

    var isEmpty: Bool {
        return elements.isEmpty
    }
}

// 实现 Queue
struct Queue<T> {
    private var elements: [T] = []

    mutating func enqueue(_ element: T) {
        elements.append(element)
    }

    mutating func dequeue() -> T? {
        return elements.isEmpty ? nil : elements.removeFirst()
    }

    func peek() -> T? {
        return elements.first
    }

    var isEmpty: Bool {
        return elements.isEmpty
    }
}

2. 避免标准库臃肿

Swift 的设计哲学之一是保持标准库的精简和高效。如果每种数据结构都在标准库中提供实现,会导致标准库变得非常庞大和复杂。相反,Swift 鼓励开发者根据具体需求自己实现或使用第三方库。

3. 泛型与扩展

Swift 的泛型和扩展机制使得开发者可以很方便地定义自己的数据结构。通过泛型,可以实现类型安全的 Stack 和 Queue,而不需要依赖标准库中的实现。

4. 社区与第三方库支持

Swift 社区中有很多高质量的第三方库提供了各种数据结构的实现,例如 Swift Algorithm Club 就包含了丰富的数据结构和算法的实现。这种模式让标准库保持精简的同时,也能满足开发者的多样化需求。

结论

虽然 Swift 标准库没有原生支持 Stack 和 Queue 数据结构,但通过利用 Swift 强大的泛型和扩展机制,开发者可以很容易地自己实现这些数据结构。再加上丰富的第三方库支持,开发者可以根据需要选择最适合自己的解决方案。

相关推荐
师太,答应老衲吧3 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
2401_865854887 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
passer__jw76711 小时前
【LeetCode】【算法】208. 实现 Trie (前缀树)
算法·leetcode
益达爱喝芬达12 小时前
力扣11.3
算法·leetcode
passer__jw76712 小时前
【LeetCode】【算法】406. 根据身高重建队列
算法·leetcode
__AtYou__12 小时前
Golang | Leetcode Golang题解之第535题TinyURL的加密与解密
leetcode·golang·题解
远望樱花兔12 小时前
【d63】【Java】【力扣】141.训练计划III
java·开发语言·leetcode
迃-幵12 小时前
力扣:225 用队列实现栈
android·javascript·leetcode
九圣残炎12 小时前
【从零开始的LeetCode-算法】3254. 长度为 K 的子数组的能量值 I
java·算法·leetcode
vir0214 小时前
找出目标值在数组中的开始和结束位置(二分查找)
数据结构·c++·算法·leetcode