数据结构和算法 字符串匹配_算法和数据结构面试准备和演练—第2部分,数组和字符串...

数据结构和算法 字符串匹配

Arrrrr…。 雷(来源:Gorgaiphotography / iStock)

在我之前的文章: 算法和数据结构面试准备和演练—第1部分中 ,我们讨论了如何进行复杂性时空分析,并通过示例介绍了常见的Big-O因素。

在这篇文章中,我将开始深入讨论Array,并涵盖一些采访问题,并希望在阅读结束时,您对Array有一个很好的了解。 一旦我们熟悉Array,我将讨论String以及如何使用Array解决String问题。

数组是一种包含一组元素的数据结构 。 数组的最基本实现是静态数组。 之所以称为静态,是因为大小是固定的。 对特定位置的读/写访问为O(1)。

静态数组的实现
class StaticArray
def initialize(length)
self.store = Array.new(length)
end
# O(1)
def [](index)
self.store[index]
end
# O(1)
def []=(index, value)
self.store[index] = value
end
protected
attr_accessor :store
end

我们从静态数组创建动态数组,如下所示。 读/写访问也是O(1)。 让我们为其实现一些通用方法,例如pop(),push(),shift()和unshift()。 这里的关键是,当我们达到数组大小时,我们想要调整其大小并将其空间加倍,以便将新元素push()或unshift()移到数组中。

动态数组的实现
require_relative "static_array"
class DynamicArray
attr_reader :length
def initialize
@length = 0
@capacity = 8
@store = StaticArray.new(8)
end
# O(1)
def [](index)
check_index(index)
@store [index]
end
# O(1)
def []=(index, value)
check_index(index)
@store [index] = value
end
# O(1)
def pop
check_index(0)
@length -= 1
@store [length + 1]
end
# O(1) amortized ; O(n) worst case.
def push(val)
resize! if @length == @capacity
@store [ @length + 1] = val
@length += 1
end
# O(n): has to shift over all the elements.
def shift
check_index(0)
idx = 0
first_el = @store [0]
while idx < @length - 1
@store [idx] = @store [idx + 1]
idx += 1
end
@length -= 1
first_el
end
# O(n): has to shift over all the elements.
def unshift(val)
resize! if @length == @capacity
idx = @length
while idx > 0
@store [idx] = @store [idx - 1]
idx -= 1
end
@store [0] = val
@length += 1
@store
end
protected
attr_accessor :capacity, :store
attr_writer :length
def check_index(index)
raise "out of bounds" if ( @length < index + 1 || index < 0)
end
# O(n): has to copy over all the elements to the new store.
def resize!
new_store = StaticArray.new( @capacity * 2)
idx = 0
while idx < @length
new_store[idx] = @store [idx]
idx += 1
end
@store = new_store
@capacity *= 2
end
end
什么是摊销?

如果您仔细阅读,会发现代码片段中有一个关键字“摊销”。 那是什么意思? 当我们想将新元素追加(或推送)到数组并达到其大小限制时,我们希望将大小增加一倍。 但是,请resize! 方法分配更大的区域,移动整个数组,并删除前一个数组。 这是O(n)运算。 但是,如果我们仅每O(1/n)次执行一次,则平均而言,它仍然可以得出O(n * 1/n) = O(1) 。 这就是所谓的摊销成本

动态数组的时间复杂度和空间复杂度

在平均和最坏的情况下,

Access O(1)

Search O(n)

Insertion O(n) (在Array的末尾是O(1)摊销,在Array的开始或中间是O(n)

Deletion O(n)

Space O(n)

现在,我们知道访问Array中的元素的速度很快( O(1) ),而搜索/添加/删除操作则相对较慢( O(n) ),这有时需要遍历整个数组。

环形缓冲区

它是一种使用静态数组的数据结构,就好像它是端对端连接的一样。

require_relative "static_array"
class RingBuffer
attr_reader :length
def initialize
@length = 0
@capacity = 8
@start_idx = 0
@store = StaticArray.new( @capacity )
end
# O(1)
def [](index)
check_index(index)
ring_index = (index + @start_idx ) % @capacity
@store [ring_index]
end
# O(1)
def []=(index, val)
check_index(index)
ring_index = (index + @start_idx ) % @capacity
@store [ring_index] = val
end
# O(1)
def pop
check_index(0)
@length -= 1;
val = @store [( @length + @start_idx ) % @capacity ]
@store [( @length + @start_idx ) % @capacity ] = nil
val
end
# O(1) amortized
def push(val)
resize! if @length == @capacity
@store [( @length + @start_idx ) % @capacity ] = val
@length += 1
end
# O(1)
def shift
check_index(0)
val = @store [ @start_idx ]
@store [ @start_idx ] = nil
@start_idx = ( @start_idx + 1) % @capacity
@length -= 1
val
end
# O(1) amortized
def unshift(val)
resize! if @length == @capacity
@start_idx = ( @start_idx - 1) % @capacity
@store [ @start_idx ] = val
@length += 1
val
end
protected
attr_accessor :capacity, :start_idx, :store
attr_writer :length
def check_index(index)
raise "index out of bounds" if (index < 0 || index > @length - 1)
end
def resize!
new_store = StaticArray.new( @capacity * 2)
idx = 0
while idx < @length
new_store[idx] = @store [( @start_idx + idx) % @capacity ]
idx += 1
end
@store = new_store
@start_idx = 0
@capacity *= 2
end
end

要掌握Array数据结构和问题,我们至少需要非常熟悉:

  1. 循环操作。
  2. 使用指针记录位置的感觉。
  3. 交换技术。
  4. 基本数学
  5. 常见的数组方法及其时间复杂度,例如pop(),push(),shift(),unshift(),forEach(),sort(),slice(),splice(),reverse(),concat() ,filter(),map()等等。

使用数组的一些优点:

●恒定时间访问并允许随机访问

●分组类似项目

还有一些缺点...

●对于大型阵列,插入和删除可能会很昂贵

●动态数组需要调整大小,并且受分配的大小限制

足够说了,这是一些针对您的练习的热门面试问题:

  1. 移动零-给定一个数字数组,编写一个函数,将所有0移到其结尾,同时保持非零元素的相对顺序。 ( 思考过程和解决方案
  2. 股票101 —何时购买/出售股票? 给定一个数组,其中包含股票的每日价格。 尝试找到最大的利润。 ( 思考过程和解决方案
  3. 查找重复项—给定一个数字数组,如果任何数字在数组中出现多次,则返回true,否则返回false。 ( 思考过程和解决方案

现在我们了解了Array,下面我们来谈谈String,它只是基于字符的Array 。 您只需要学习解决数组问题的技术即可,并且天生就是一名String Master!

在深入研究与String相关的问题之前,我们需要熟悉以下内容:

  1. 与字符串相关的方法,即charAt(),include(),trim(),concat(),slice(),split(),substring(),toUpperCase(),toLowerCase(),toString()等。
  2. 两个指针。
  3. 在数组中交换元素。
  4. 递归。

在我的下一篇文章中 我将讨论队列,堆栈和链接列表的数据结构。

你走之前 -

没有比在Medium( Victor Lin )上追随我更好的支持我的方法了。 让我知道我应该写更多!

您知道按下down按钮最多可以放弃50?吗? 如果您再次喜欢这篇文章,请尝试一下!

翻译自: https://hackernoon.com/algorithms-and-data-structures-interview-preparation-walkthrough-part-2-array-and-string-80f28e095ca8

数据结构和算法 字符串匹配

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值